1
4
5# include "luametatex.h"
6
7static void tex_aux_scan_expr (halfword level);
8static void tex_aux_scan_expression (int level);
9
10
13
14inline static void tex_push_back(halfword tok, halfword cmd, halfword chr)
15{
16 if (cmd != spacer_cmd && tok != deep_frozen_relax_token && ! (cmd == relax_cmd && chr == no_relax_code)) {
17 tex_back_input(tok);
18 }
19}
20
21
32
33
34
35void tex_scan_left_brace(void)
36{
37
38 while(1) {
39 tex_get_x_token();
40 switch (cur_cmd) {
41 case left_brace_cmd:
42
43 return;
44 case spacer_cmd:
45 case relax_cmd:
46
47 break;
48 default:
49
50 tex_handle_error(
51 back_error_type,
52 "Missing { inserted",
53 "A left brace was mandatory here, so I've put one in."
54 );
55 cur_tok = left_brace_token + '{';
56 cur_cmd = left_brace_cmd;
57 cur_chr = '{';
58 ++lmt_input_state.align_state;
59 return;
60 }
61 }
62}
63
64
70
71void tex_scan_optional_equals(void)
72{
73
74 do {
75 tex_get_x_token();
76 } while (cur_cmd == spacer_cmd);
77 if (cur_tok != equal_token) {
78 tex_back_input(cur_tok);
79 }
80}
81
82
87
88static void tex_aux_mu_error(int n)
89{
90 tex_handle_error(
91 normal_error_type,
92 "Incompatible glue units (case %i)",
93 n,
94 "I'm going to assume that 1mu=1pt when they're mixed."
95 );
96}
97
98
131
132scanner_state_info lmt_scanner_state = {
133 .current_cmd = 0,
134 .current_chr = 0,
135 .current_cs = 0,
136
137 .current_tok = 0,
138 .current_val = 0,
139 .current_val_level = 0,
140 .current_box = 0,
141 .last_cs_name = 0,
142 .arithmic_error = 0,
143 .expression_depth = 0,
144};
145
146
157
158inline static void tex_aux_downgrade_cur_val(int level, int succeeded, int negative)
159{
160 switch (cur_val_level) {
161 case posit_val_level:
162 if (negative) {
163 cur_val = tex_posit_neg(cur_val);
164 }
165 switch (level) {
166 case dimension_val_level:
167 cur_val = tex_posit_to_dimension(cur_val);
168 cur_val_level = level;
169 break;
170 case integer_val_level:
171 case attribute_val_level:
172 cur_val = (halfword) tex_posit_to_integer(cur_val);
173 cur_val_level = level;
174 break;
175 }
176
177
178
179 break;
180 case integer_val_level:
181 if (cur_val_level > level) {
182 cur_val_level = level;
183 }
184 if (negative) {
185 cur_val = -cur_val;
186 }
187 if (level == posit_val_level) {
188 cur_val = tex_integer_to_posit(cur_val).v;
189 }
190 break;
191 case attribute_val_level:
192 if (cur_val_level > level) {
193 cur_val_level = level;
194 }
195 if (negative) {
196 cur_val = -cur_val;
197 }
198 if (level == posit_val_level) {
199 cur_val = tex_integer_to_posit(cur_val).v;
200 }
201 break;
202 case dimension_val_level:
203 if (cur_val_level > level) {
204 cur_val_level = level;
205 }
206 if (negative) {
207 cur_val = -cur_val;
208 }
209 if (level == posit_val_level) {
210 cur_val = tex_dimension_to_posit(cur_val).v;
211 }
212 break;
213 case muglue_val_level:
214 if (level == glue_val_level) {
215 goto COPYGLUE;
216 }
217 case glue_val_level:
218 if (level == posit_val_level) {
219 cur_val_level = level;
220 cur_val = tex_dimension_to_posit(negative ? - glue_amount(cur_val) : glue_amount(cur_val)).v;
221 } else if (cur_val_level > level) {
222
223 cur_val_level = level;
224 cur_val = negative ? - glue_amount(cur_val) : glue_amount(cur_val);
225 } else {
226 COPYGLUE:
227 if (succeeded == 1) {
228 cur_val = tex_new_glue_spec_node(cur_val);
229 }
230 if (negative) {
231 glue_amount(cur_val) = -glue_amount(cur_val);
232 glue_stretch(cur_val) = -glue_stretch(cur_val);
233 glue_shrink(cur_val) = -glue_shrink(cur_val);
234 }
235 }
236 break;
237 case token_val_level:
238 case font_val_level:
239 case mathspec_val_level:
240 case fontspec_val_level:
241
246 break;
247
248
249
250
251 default:
252 tex_confusion("downgrade");
253 }
254}
255
256
265
266static void tex_aux_set_cur_val_by_lua_value_cmd(halfword index, halfword property)
267{
268 int category = lua_value_none_code;
269 halfword value = 0;
270 strnumber u = tex_save_cur_string();
271 lmt_token_state.luacstrings = 0;
272 category = lmt_function_call_by_category(index, property, &value);
273 switch (category) {
274 case lua_value_none_code:
275 cur_val_level = no_val_level;
276 break;
277 case lua_value_integer_code:
278 case lua_value_cardinal_code:
279 cur_val_level = integer_val_level;
280 break;
281 case lua_value_dimension_code:
282 cur_val_level = dimension_val_level;
283 break;
284 case lua_value_skip_code:
285 cur_val_level = glue_val_level;
286 break;
287 case lua_value_boolean_code:
288
289 value = value ? 1 : 0;
290 cur_val_level = integer_val_level;
291 break;
292 case lua_value_float_code:
293 cur_val_level = posit_val_level;
294 break;
295 case lua_value_string_code:
296 cur_val_level = no_val_level;
297 break;
298 case lua_value_node_code:
299 case lua_value_direct_code:
300 if (value) {
301 switch (node_type(value)) {
302 case hlist_node:
303 case vlist_node:
304 case whatsit_node:
305 case rule_node:
306 cur_val_level = list_val_level;
307 break;
308 default:
309
310 value = null;
311 cur_val_level = no_val_level;
312 break;
313 }
314 } else {
315 value = null;
316 cur_val_level = no_val_level;
317 }
318 break;
319 case lua_value_conditional_code:
320
321 default:
322 cur_val_level = no_val_level;
323 break;
324 }
325 cur_val = value;
326 tex_restore_cur_string(u);
327 if (lmt_token_state.luacstrings > 0) {
328 tex_lua_string_start();
329 }
330}
331
332halfword tex_scan_lua_value(int index)
333{
334 tex_aux_set_cur_val_by_lua_value_cmd(index, 0);
335 return cur_val_level;
336}
337
338static halfword tex_aux_scan_register_index(void)
339{
340 do {
341 tex_get_x_token();
342 } while (cur_cmd == spacer_cmd);
343 switch (cur_cmd) {
344 case register_toks_cmd : return cur_chr - register_toks_base;
345 case register_integer_cmd : return cur_chr - register_integer_base;
346 case register_attribute_cmd : return cur_chr - register_attribute_base;
347 case register_posit_cmd : return cur_chr - register_posit_base;
348 case register_dimension_cmd : return cur_chr - register_dimension_base;
349 case register_glue_cmd : return cur_chr - register_glue_base;
350 case register_muglue_cmd : return cur_chr - register_muglue_base;
351 case char_given_cmd : return cur_chr;
352 case mathspec_cmd : return tex_get_math_spec(cur_chr).character_value;
353 case integer_cmd : return cur_chr;
354
355 case posit_cmd : return cur_chr;
356 case dimension_cmd : return cur_chr;
357 default : return -1;
358 }
359}
360
361static halfword tex_aux_scan_character_index(void)
362{
363 halfword result = -1;
364 tex_get_token();
365 if (cur_tok < cs_token_flag) {
366 result = cur_chr;
367 } else if (cur_cmd == char_given_cmd) {
368 result = cur_chr;
369 } else if (cur_cmd == mathspec_cmd) {
370 result = tex_get_math_spec(cur_chr).character_value;
371 } else {
372 strnumber txt = cs_text(cur_tok - cs_token_flag);
373 if (tex_single_letter(txt)) {
374 result = aux_str2uni(str_string(txt));
375 } else if (tex_is_active_cs(txt)) {
376 result = active_cs_value(txt);
377 } else {
378 result = max_character_code + 1;
379 }
380 }
381 return result > max_character_code ? -1 : result;
382}
383
384
390
391static int tex_aux_set_cur_val_by_some_cmd(int code)
392{
393 switch (code) {
394 case lastpenalty_code:
395 cur_val_level = integer_val_level;
396 goto COMMON;
397 case lastkern_code:
398 cur_val_level = dimension_val_level;
399 goto COMMON;
400 case lastskip_code:
401 cur_val_level = glue_val_level;
402 goto COMMON;
403 case lastboundary_code:
404 cur_val_level = integer_val_level;
405 COMMON:
406 {
407 cur_val = 0;
408 if (cur_list.tail != contribute_head && ! (cur_list.tail && node_type(cur_list.tail) == glyph_node) && cur_list.mode != nomode) {
409 switch (code) {
410 case lastpenalty_code:
411 if (node_type(cur_list.tail) == penalty_node) {
412 cur_val = penalty_amount(cur_list.tail);
413 }
414 break;
415 case lastkern_code:
416 if (node_type(cur_list.tail) == kern_node) {
417 cur_val = kern_amount(cur_list.tail);
418 }
419 break;
420 case lastskip_code:
421 if (node_type(cur_list.tail) == glue_node) {
422 cur_val = cur_list.tail;
423 if (node_subtype(cur_list.tail) == mu_glue) {
424 cur_val_level = muglue_val_level;
425 }
426 }
427 break;
428 case lastboundary_code:
429 if (node_type(cur_list.tail) == boundary_node && node_subtype(cur_list.tail) == user_boundary) {
430 cur_val = boundary_data(cur_list.tail);
431 }
432 break;
433 }
434 } else if (cur_list.mode == vmode && cur_list.tail == cur_list.head) {
435 switch (code) {
436 case lastpenalty_code:
437 cur_val = lmt_page_builder_state.last_penalty;
438 break;
439 case lastkern_code:
440 cur_val = lmt_page_builder_state.last_kern;
441 break;
442 case lastskip_code:
443 if (lmt_page_builder_state.last_glue != max_halfword) {
444 cur_val = lmt_page_builder_state.last_glue;
445 }
446 break;
447 case lastboundary_code:
448 cur_val = lmt_page_builder_state.last_boundary;
449 break;
450 }
451 }
452 break;
453 }
454 case last_node_type_code:
455
459 {
460 cur_val_level = integer_val_level;
461 if (cur_list.tail != contribute_head && cur_list.mode != nomode) {
462 cur_val = node_type(cur_list.tail);
463 } else if (cur_list.mode == vmode && cur_list.tail == cur_list.head) {
464 cur_val = lmt_page_builder_state.last_node_type;
465 } else if (cur_list.tail == cur_list.head || cur_list.mode == nomode) {
466 cur_val = -1;
467 } else {
468 cur_val = node_type(cur_list.tail);
469 }
470 break;
471 }
472 case last_node_subtype_code:
473 {
474 cur_val_level = integer_val_level;
475 if (cur_list.tail != contribute_head && cur_list.mode != nomode) {
476 cur_val = node_subtype(cur_list.tail);
477 } else if (cur_list.mode == vmode && cur_list.tail == cur_list.head) {
478 cur_val = lmt_page_builder_state.last_node_subtype;
479 } else if (cur_list.tail == cur_list.head || cur_list.mode == nomode) {
480 cur_val = -1;
481 } else {
482 cur_val = node_subtype(cur_list.tail);
483 }
484 break;
485 }
486 case input_line_no_code:
487 cur_val = lmt_input_state.input_line;
488 cur_val_level = integer_val_level;
489 break;
490 case badness_code:
491 cur_val = lmt_packaging_state.last_badness;
492 cur_val_level = integer_val_level;
493 break;
494 case overshoot_code:
495 cur_val = lmt_packaging_state.last_overshoot;
496 cur_val_level = dimension_val_level;
497 break;
498 case luatex_version_code:
499 cur_val = lmt_version_state.version;
500 cur_val_level = integer_val_level;
501 break;
502 case luatex_revision_code:
503 cur_val = lmt_version_state.revision;
504 cur_val_level = integer_val_level;
505 break;
506 case current_group_level_code:
507 cur_val = cur_level - level_one;
508 cur_val_level = integer_val_level;
509 break;
510 case current_group_type_code:
511 cur_val = cur_group;
512 cur_val_level = integer_val_level;
513 break;
514 case current_stack_size_code:
515 cur_val = lmt_save_state.save_stack_data.ptr;
516 cur_val_level = integer_val_level;
517 break;
518 case current_if_level_code:
519 {
520 halfword q = lmt_condition_state.cond_ptr;
521 cur_val = 0;
522 while (q) {
523 ++cur_val;
524 q = node_next(q);
525 }
526 cur_val_level = integer_val_level;
527 break;
528 }
529 case current_if_type_code:
530 {
531
538 cur_val = lmt_condition_state.cond_ptr ? (lmt_condition_state.cur_if - first_real_if_test_code) : -1;
539 cur_val_level = integer_val_level;
540 break;
541 }
542 case current_if_branch_code:
543 {
544 switch (lmt_condition_state.if_limit) {
545 case if_code:
546 cur_val = 0;
547 break;
548 case fi_code:
549 cur_val = -1;
550 break;
551 case else_code:
552 case or_code:
553 case or_else_code:
554 case or_unless_code:
555 cur_val = 1;
556 break;
557 default:
558 cur_val = 0;
559 break;
560 }
561 cur_val_level = integer_val_level;
562 break;
563 }
564 case glue_stretch_order_code:
565 case glue_shrink_order_code:
566 {
567
572 halfword q = tex_scan_glue(glue_val_level, 0, 0);
573 cur_val = (code == glue_stretch_order_code) ? glue_stretch_order(q) : glue_shrink_order(q);
574 tex_flush_node(q);
575 cur_val_level = integer_val_level;
576 break;
577 }
578 case font_id_code:
579 {
580 cur_val = tex_scan_font_identifier(NULL);
581 cur_val_level = integer_val_level;
582 break;
583 }
584 case glyph_x_scaled_code:
585 {
586 cur_val = tex_font_x_scaled(tex_scan_dimension(0, 0, 0, 1, NULL));
587 cur_val_level = dimension_val_level;
588 break;
589 }
590 case glyph_y_scaled_code:
591 {
592 cur_val = tex_font_y_scaled(tex_scan_dimension(0, 0, 0, 1, NULL));
593 cur_val_level = dimension_val_level;
594 break;
595 }
596 case font_spec_id_code:
597 case font_spec_scale_code:
598 case font_spec_xscale_code:
599 case font_spec_yscale_code:
600 case font_spec_slant_code:
601 case font_spec_weight_code:
602 {
603 halfword fs = tex_scan_fontspec_identifier();
604 if (fs) {
605 switch (code) {
606 case font_spec_id_code:
607 cur_val = font_spec_identifier(fs);
608 break;
609 case font_spec_scale_code:
610 cur_val = font_spec_scale(fs);
611 break;
612 case font_spec_xscale_code:
613 cur_val = font_spec_x_scale(fs);
614 break;
615 case font_spec_yscale_code:
616 cur_val = font_spec_y_scale(fs);
617 break;
618 case font_spec_slant_code:
619 cur_val = font_spec_slant(fs);
620 break;
621 case font_spec_weight_code:
622 cur_val = font_spec_weight(fs);
623 break;
624 }
625 } else {
626 cur_val = 0;
627 }
628 cur_val_level = integer_val_level;
629 break;
630 }
631 case font_char_wd_code:
632 case font_char_ht_code:
633 case font_char_dp_code:
634 case font_char_ic_code:
635 case font_char_ta_code:
636 case font_char_ba_code:
637 case scaled_font_char_wd_code:
638 case scaled_font_char_ht_code:
639 case scaled_font_char_dp_code:
640 case scaled_font_char_ic_code:
641 case scaled_font_char_ta_code:
642 case scaled_font_char_ba_code:
643 {
644 halfword fnt = tex_scan_font_identifier(NULL);
645 halfword chr = tex_scan_char_number(0);
646 if (tex_char_exists(fnt, chr)) {
647 switch (code) {
648 case font_char_wd_code:
649 case scaled_font_char_wd_code:
650 cur_val = tex_char_width_from_font(fnt, chr);
651 break;
652 case font_char_ht_code:
653 case scaled_font_char_ht_code:
654 cur_val = tex_char_height_from_font(fnt, chr);
655 break;
656 case font_char_dp_code:
657 case scaled_font_char_dp_code:
658 cur_val = tex_char_depth_from_font(fnt, chr);
659 break;
660 case font_char_ic_code:
661 case scaled_font_char_ic_code:
662 cur_val = tex_char_italic_from_font(fnt, chr);
663 break;
664 case font_char_ta_code:
665 case scaled_font_char_ta_code:
666 cur_val = tex_char_top_anchor_from_font(fnt, chr);
667 break;
668 case font_char_ba_code:
669 case scaled_font_char_ba_code:
670 cur_val = tex_char_bottom_anchor_from_font(fnt, chr);
671 break;
672 }
673 switch (code) {
674 case scaled_font_char_wd_code:
675 case scaled_font_char_ic_code:
676 case scaled_font_char_ta_code:
677 case scaled_font_char_ba_code:
678 cur_val = tex_font_x_scaled(cur_val);
679 break;
680 case scaled_font_char_ht_code:
681 case scaled_font_char_dp_code:
682 cur_val = tex_font_y_scaled(cur_val);
683 break;
684 }
685 } else {
686 cur_val = 0;
687 }
688 cur_val_level = dimension_val_level;
689 break;
690 }
691 case font_size_code:
692 {
693 halfword fnt = tex_scan_font_identifier(NULL);
694 cur_val = font_size(fnt);
695 cur_val_level = dimension_val_level;
696 break;
697 }
698 case font_math_control_code:
699 {
700 halfword fnt = tex_scan_font_identifier(NULL);
701 cur_val = font_mathcontrol(fnt);
702 cur_val_level = integer_val_level;
703 break;
704 }
705 case font_text_control_code:
706 {
707 halfword fnt = tex_scan_font_identifier(NULL);
708 cur_val = font_textcontrol(fnt);
709 cur_val_level = integer_val_level;
710 break;
711 }
712 case math_scale_code:
713 {
714 halfword fnt = tex_scan_font_identifier(NULL);
715 if (tex_is_valid_font(fnt)) {
716 cur_val = tex_get_math_font_scale(fnt, tex_math_style_to_size(tex_current_math_style()));
717 } else {
718 cur_val = 1000;
719 }
720 cur_val_level = integer_val_level;
721 break;
722 }
723 case math_style_code:
724 {
725 cur_val = tex_current_math_style();
726 if (cur_val < 0) {
727 cur_val = text_style;
728 }
729 cur_val_level = integer_val_level;
730 break;
731 }
732 case math_main_style_code:
733 {
734 cur_val = tex_current_math_main_style();
735 if (cur_val < 0) {
736 cur_val = text_style;
737 }
738 cur_val_level = integer_val_level;
739 break;
740 }
741 case math_style_font_id_code:
742 {
743 halfword style = tex_scan_math_style_identifier(0, 0);
744 halfword family = tex_scan_math_family_number();
745 cur_val = tex_fam_fnt(family, tex_size_of_style(style));
746 cur_val_level = integer_val_level;
747 break;
748 }
749 case math_stack_style_code:
750 {
751 cur_val = tex_math_style_variant(cur_list.math_style, math_parameter_stack_variant);
752 if (cur_val < 0) {
753 cur_val = text_style;
754 }
755 cur_val_level = integer_val_level;
756 break;
757 }
758 case math_char_class_code:
759 case math_char_fam_code:
760 case math_char_slot_code:
761
762 {
763 mathcodeval mval = tex_no_math_code();
764 mathdictval dval = { 0, 0, 0 };
765 if (tex_scan_math_cmd_val(&mval, &dval)) {
766 switch (code) {
767 case math_char_class_code:
768 cur_val = mval.class_value;
769 break;
770 case math_char_fam_code:
771 cur_val = mval.family_value;
772 break;
773 case math_char_slot_code:
774 cur_val = mval.character_value;
775 break;
776 default:
777 cur_val = 0;
778 break;
779 }
780 } else {
781 cur_val = 0;
782 }
783 cur_val_level = integer_val_level;
784 break;
785 }
786 case scaled_slant_per_point_code:
787 case scaled_interword_space_code:
788 case scaled_interword_stretch_code:
789 case scaled_interword_shrink_code:
790 case scaled_ex_height_code:
791 case scaled_em_width_code:
792 case scaled_extra_space_code:
793 {
794 cur_val = tex_get_scaled_parameter(cur_font_par, (code - scaled_slant_per_point_code + 1));
795 cur_val_level = dimension_val_level;
796 break;
797 }
798 case scaled_math_axis_code:
799 case scaled_math_ex_height_code:
800 case scaled_math_em_width_code:
801 {
802 halfword style = tex_scan_math_style_identifier(0, 0);
803 switch (code) {
804 case scaled_math_axis_code:
805 cur_val = tex_math_parameter_x_scaled(style, math_parameter_axis);
806 break;
807 case scaled_math_ex_height_code:
808 cur_val = tex_math_parameter_y_scaled(style, math_parameter_exheight);
809 break;
810 case scaled_math_em_width_code:
811 cur_val = tex_math_parameter_x_scaled(style, math_parameter_quad);
812 break;
813 }
814 cur_val_level = dimension_val_level;
815 break;
816 }
817 case last_arguments_code:
818 {
819 cur_val = lmt_expand_state.arguments;
820 cur_val_level = integer_val_level;
821 break;
822 }
823 case parameter_count_code:
824 {
825 cur_val = tex_get_parameter_count();
826 cur_val_level = integer_val_level;
827 break;
828 }
829 case parameter_index_code:
830 {
831 cur_val = tex_get_parameter_index(tex_scan_parameter_index());
832 cur_val_level = integer_val_level;
833 break;
834 }
835
847 case insert_progress_code:
848 {
849 cur_val = tex_get_insert_progress(tex_scan_integer(0, NULL));
850 cur_val_level = dimension_val_level;
851 break;
852 }
853 case left_margin_kern_code:
854 case right_margin_kern_code:
855 {
856 halfword v = tex_scan_integer(0, NULL);
857 halfword b = box_register(v);
858 if (b && (node_type(b) == hlist_node)) {
859 if (code == left_margin_kern_code) {
860 cur_val = tex_left_marginkern(box_list(b));
861 } else {
862 cur_val = tex_right_marginkern(box_list(b));
863 }
864 } else {
865 tex_normal_error("marginkern", "a hbox expected");
866 cur_val = 0;
867 }
868 cur_val_level = dimension_val_level;
869 break;
870 }
871 case par_shape_length_code:
872 case par_shape_indent_code:
873 case par_shape_dimension_code:
874 {
875 halfword q = code - par_shape_length_code;
876 halfword v = tex_scan_integer(0, NULL);
877 if (v <= 0 || ! par_shape_par) {
878 v = 0;
879 } else {
880 int n = specification_count(par_shape_par);
881 if (q == 2) {
882 q = v % 2;
883 v = (v + q) / 2;
884 }
885 if (v > n) {
886 v = n;
887 }
888 if (n == 0) {
889 v = 0;
890 } else if (q) {
891 v = tex_get_specification_indent(par_shape_par, v);
892 } else {
893 v = tex_get_specification_width(par_shape_par, v);
894 }
895 }
896 cur_val = v;
897 cur_val_level = dimension_val_level;
898 break;
899 }
900 case glue_stretch_code:
901 case glue_shrink_code:
902 {
903 halfword q = tex_scan_glue(glue_val_level, 0, 0);
904 cur_val = code == glue_stretch_code ? glue_stretch(q) : glue_shrink(q);
905 tex_flush_node(q);
906 cur_val_level = dimension_val_level;
907 break;
908 }
909 case mu_to_glue_code:
910 cur_val = tex_scan_glue(muglue_val_level, 0, 0);
911 cur_val_level = glue_val_level;
912 return 1;
913 case glue_to_mu_code:
914 cur_val = tex_scan_glue(glue_val_level, 0, 0);
915 cur_val_level = muglue_val_level;
916 return 1;
917 case numexpr_code:
918
919 tex_aux_scan_expr(integer_val_level);
920 return 1;
921 case posexpr_code:
922 tex_aux_scan_expr(posit_val_level);
923 return 1;
924 case dimexpr_code:
925 tex_aux_scan_expr(dimension_val_level);
926 return 1;
927 case glueexpr_code:
928 tex_aux_scan_expr(glue_val_level);
929 return 1;
930 case muexpr_code:
931 tex_aux_scan_expr(muglue_val_level);
932 return 1;
933 case numexpression_code:
934 tex_aux_scan_expression(integer_val_level);
935 return 1;
936 case dimexpression_code:
937 tex_aux_scan_expression(dimension_val_level);
938 return 1;
939
940
941
942
943 case numeric_scale_code:
944 cur_val_level = integer_val_level;
945 cur_val = tex_scan_scale(0);
946 return 1;
947 case numeric_scaled_code:
948 {
949 scaled n = tex_scan_scale(0);
950 scaled i = tex_scan_integer(0, NULL);
951 cur_val_level = integer_val_level;
952 cur_val = tex_xn_over_d(i, n, scaling_factor);
953 }
954 return 1;
955 case index_of_register_code:
956 cur_val = tex_aux_scan_register_index();
957 cur_val_level = integer_val_level;
958 return 1;
959 case index_of_character_code:
960 cur_val = tex_aux_scan_character_index();
961 cur_val_level = integer_val_level;
962 return 1;
963 case last_chk_integer_code:
964 cur_val_level = integer_val_level;
965 cur_val = lmt_condition_state.chk_integer;
966 return 1;
967 case last_chk_dimension_code:
968 cur_val_level = dimension_val_level;
969 cur_val = lmt_condition_state.chk_dimension;
970 return 1;
971 case last_left_class_code:
972 cur_val_level = integer_val_level;
973 cur_val = lmt_math_state.last_left;
974 if (! valid_math_class_code(cur_val)) {
975 cur_val = unset_noad_class;
976 }
977 return 1;
978 case last_right_class_code:
979 cur_val_level = integer_val_level;
980 cur_val = lmt_math_state.last_right;
981 if (! valid_math_class_code(cur_val)) {
982 cur_val = unset_noad_class;
983 }
984 return 1;
985 case last_atom_class_code:
986 cur_val_level = integer_val_level;
987 cur_val = lmt_math_state.last_atom;
988 if (! valid_math_class_code(cur_val)) {
989 cur_val = unset_noad_class;
990 }
991 return 1;
992 case nested_loop_iterator_code:
993 cur_val = tex_nested_loop_iterator();
994 cur_val_level = integer_val_level;
995 return 1;
996 case previous_loop_iterator_code:
997 cur_val = tex_previous_loop_iterator();
998 cur_val_level = integer_val_level;
999 return 1;
1000 case current_loop_iterator_code:
1001 case last_loop_iterator_code:
1002 cur_val_level = integer_val_level;
1003 cur_val = lmt_main_control_state.loop_iterator;
1004 return 1;
1005 case current_loop_nesting_code:
1006 cur_val_level = integer_val_level;
1007 cur_val = lmt_main_control_state.loop_nesting;
1008 return 1;
1009 case last_par_trigger_code:
1010 cur_val_level = integer_val_level;
1011 cur_val = lmt_main_control_state.last_par_trigger;
1012 return 1;
1013 case last_par_context_code:
1014 cur_val_level = integer_val_level;
1015 cur_val = lmt_main_control_state.last_par_context;
1016 return 1;
1017 case last_page_extra_code:
1018 cur_val_level = integer_val_level;
1019 cur_val = lmt_page_builder_state.last_extra_used;
1020 return 1;
1021 case math_atom_glue_code:
1022 {
1023 halfword style = tex_scan_math_style_identifier(0, 0);
1024 halfword leftclass = tex_scan_math_class_number(0);
1025 halfword rightclass = tex_scan_math_class_number(0);
1026 cur_val = tex_math_spacing_glue(leftclass, rightclass, style);
1027 cur_val_level = muglue_val_level;
1028 break;
1029 }
1030 }
1031 return 0;
1032}
1033
1034static void tex_aux_set_cur_val_by_auxiliary_cmd(int code)
1035{
1036 switch (code) {
1037 case space_factor_code:
1038 if (is_h_mode(cur_list.mode)) {
1039 cur_val = cur_list.space_factor;
1040 } else {
1041 tex_handle_error(normal_error_type, "Improper %C", auxiliary_cmd, code,
1042 "You can refer to \\spacefactor only in horizontal mode and not in \n"
1043 "inside \\write. So I'm forgetting what you said and using zero instead."
1044 );
1045 cur_val = 0;
1046 }
1047 cur_val_level = integer_val_level;
1048 break;
1049 case prev_depth_code:
1050 if (is_v_mode(cur_list.mode)) {
1051 cur_val = cur_list.prev_depth;
1052 } else {
1053 tex_handle_error(normal_error_type, "Improper %C", auxiliary_cmd, code,
1054 "You can refer to \\prevdepth only in horizontal mode and not in \n"
1055 "inside \\write. So I'm forgetting what you said and using zero instead."
1056 );
1057 cur_val = 0;
1058 }
1059 cur_val_level = dimension_val_level;
1060 break;
1061 case prev_graf_code:
1062 if (cur_list.mode == nomode) {
1063
1064 cur_val = 0;
1065 } else {
1066 cur_val = lmt_nest_state.nest[tex_vmode_nest_index()].prev_graf;
1067 }
1068 cur_val_level = integer_val_level;
1069 break;
1070 case interaction_mode_code:
1071 cur_val = lmt_error_state.interaction;
1072 cur_val_level = integer_val_level;
1073 break;
1074 case insert_mode_code:
1075 cur_val = lmt_insert_state.mode;
1076 cur_val_level = integer_val_level;
1077 break;
1078 }
1079}
1080
1081static void tex_aux_set_cur_val_by_specification_cmd(int code)
1082{
1083 switch (code) {
1084 case internal_specification_location(par_shape_code):
1085 {
1086 cur_val = tex_get_specification_count(par_shape_par);
1087 break;
1088 }
1089 case internal_specification_location(par_passes_code):
1090 {
1091 cur_val = tex_get_specification_count(par_passes_par);
1092 break;
1093 }
1094 default:
1095 {
1096 halfword v = tex_scan_integer(0, NULL);
1097 halfword e = eq_value(code);
1098 if ((! e) || (v < 0)) {
1099 cur_val = 0;
1100 } else {
1101 cur_val = tex_get_specification_penalty(e, v > specification_count(e) ? specification_count(e) : v);
1102 }
1103 break;
1104 }
1105 }
1106 cur_val_level = integer_val_level;
1107}
1108
1109# define page_state_okay (lmt_page_builder_state.contents == contribute_nothing && ! lmt_page_builder_state.output_active)
1110
1111static void tex_aux_set_cur_val_by_page_property_cmd(int code)
1112{
1113 switch (code) {
1114 case page_goal_code:
1115 cur_val = page_state_okay ? max_dimension : lmt_page_builder_state.goal;
1116 cur_val_level = dimension_val_level;
1117 break;
1118 case page_vsize_code:
1119 cur_val = page_state_okay ? 0 : lmt_page_builder_state.vsize;
1120 cur_val_level = dimension_val_level;
1121 break;
1122 case page_total_code:
1123 cur_val = page_state_okay ? 0 : lmt_page_builder_state.total;
1124 cur_val_level = dimension_val_level;
1125 break;
1126 case page_excess_code:
1127 cur_val = page_state_okay ? 0 : lmt_page_builder_state.excess;
1128 cur_val_level = dimension_val_level;
1129 break;
1130 case page_depth_code:
1131 cur_val = page_state_okay ? 0 : lmt_page_builder_state.depth;
1132 cur_val_level = dimension_val_level;
1133 break;
1134 case page_stretch_code:
1135 cur_val = page_state_okay ? 0 : lmt_page_builder_state.stretch;
1136 cur_val_level = dimension_val_level;
1137 break;
1138 case page_fistretch_code:
1139 cur_val = page_state_okay ? 0 : lmt_page_builder_state.fistretch;
1140 cur_val_level = dimension_val_level;
1141 break;
1142 case page_filstretch_code:
1143 cur_val = page_state_okay ? 0 : lmt_page_builder_state.filstretch;
1144 cur_val_level = dimension_val_level;
1145 break;
1146 case page_fillstretch_code:
1147 cur_val = page_state_okay ? 0 : lmt_page_builder_state.fillstretch;
1148 cur_val_level = dimension_val_level;
1149 break;
1150 case page_filllstretch_code:
1151 cur_val = page_state_okay ? 0 : lmt_page_builder_state.filllstretch;
1152 cur_val_level = dimension_val_level;
1153 break;
1154 case page_shrink_code:
1155 cur_val = page_state_okay ? 0 : lmt_page_builder_state.shrink;
1156 cur_val_level = dimension_val_level;
1157 break;
1158 case page_last_height_code:
1159 cur_val = page_state_okay ? 0 : lmt_page_builder_state.last_height;
1160 cur_val_level = dimension_val_level;
1161 break;
1162 case page_last_depth_code:
1163 cur_val = page_state_okay ? 0 : lmt_page_builder_state.last_depth;
1164 cur_val_level = dimension_val_level;
1165 break;
1166 case page_last_stretch_code:
1167 cur_val = page_state_okay ? 0 : lmt_page_builder_state.last_stretch;
1168 cur_val_level = dimension_val_level;
1169 break;
1170 case page_last_fistretch_code:
1171 cur_val = page_state_okay ? 0 : lmt_page_builder_state.last_fistretch;
1172 cur_val_level = dimension_val_level;
1173 break;
1174 case page_last_filstretch_code:
1175 cur_val = page_state_okay ? 0 : lmt_page_builder_state.last_filstretch;
1176 cur_val_level = dimension_val_level;
1177 break;
1178 case page_last_fillstretch_code:
1179 cur_val = page_state_okay ? 0 : lmt_page_builder_state.last_fillstretch;
1180 cur_val_level = dimension_val_level;
1181 break;
1182 case page_last_filllstretch_code:
1183 cur_val = page_state_okay ? 0 : lmt_page_builder_state.last_filllstretch;
1184 cur_val_level = dimension_val_level;
1185 break;
1186 case page_last_shrink_code:
1187 cur_val = page_state_okay ? 0 : lmt_page_builder_state.last_shrink;
1188 cur_val_level = dimension_val_level;
1189 break;
1190 case dead_cycles_code:
1191 cur_val = lmt_page_builder_state.dead_cycles;
1192 cur_val_level = integer_val_level;
1193 break;
1194 case insert_penalties_code:
1195 cur_val = lmt_page_builder_state.insert_penalties;
1196 cur_val_level = integer_val_level;
1197 break;
1198 case insert_heights_code:
1199 cur_val = lmt_page_builder_state.insert_heights;
1200 cur_val_level = dimension_val_level;
1201 break;
1202 case insert_storing_code:
1203 cur_val = lmt_insert_state.storing;
1204 cur_val_level = integer_val_level;
1205 break;
1206 case insert_distance_code:
1207 cur_val = tex_get_insert_distance(tex_scan_integer(0, NULL));
1208 cur_val_level = glue_val_level;
1209 break;
1210 case insert_multiplier_code:
1211 cur_val = tex_get_insert_multiplier(tex_scan_integer(0, NULL));
1212 cur_val_level = integer_val_level;
1213 break;
1214 case insert_limit_code:
1215 cur_val = tex_get_insert_limit(tex_scan_integer(0, NULL));
1216 cur_val_level = dimension_val_level;
1217 break;
1218 case insert_storage_code:
1219 cur_val = tex_get_insert_storage(tex_scan_integer(0, NULL));
1220 cur_val_level = integer_val_level;
1221 break;
1222 case insert_penalty_code:
1223 cur_val = tex_get_insert_penalty(tex_scan_integer(0, NULL));
1224 cur_val_level = integer_val_level;
1225 break;
1226 case insert_maxdepth_code:
1227 cur_val = tex_get_insert_maxdepth(tex_scan_integer(0, NULL));
1228 cur_val_level = dimension_val_level;
1229 break;
1230 case insert_height_code:
1231 cur_val = tex_get_insert_height(tex_scan_integer(0, NULL));
1232 cur_val_level = dimension_val_level;
1233 break;
1234 case insert_depth_code:
1235 cur_val = tex_get_insert_depth(tex_scan_integer(0, NULL));
1236 cur_val_level = dimension_val_level;
1237 break;
1238 case insert_width_code:
1239 cur_val = tex_get_insert_width(tex_scan_integer(0, NULL));
1240 cur_val_level = dimension_val_level;
1241 break;
1242 default:
1243 tex_confusion("page property");
1244 break;
1245 }
1246}
1247
1248static void tex_aux_set_cur_val_by_define_char_cmd(int code)
1249{
1250 halfword index = tex_scan_char_number(0);
1251 switch (code) {
1252 case catcode_charcode:
1253 code = tex_get_cat_code(cat_code_table_par, index);
1254 break;
1255 case lccode_charcode:
1256 code = tex_get_lc_code(index);
1257 break;
1258 case uccode_charcode:
1259 code = tex_get_uc_code(index);
1260 break;
1261 case sfcode_charcode:
1262 code = tex_get_sf_code(index);
1263 break;
1264 case hccode_charcode:
1265 code = tex_get_hc_code(index);
1266 break;
1267 case hmcode_charcode:
1268 code = tex_get_hm_code(index);
1269 break;
1270 case amcode_charcode:
1271 code = tex_get_am_code(index);
1272 break;
1273 case mathcode_charcode:
1274 case extmathcode_charcode:
1275 code = tex_get_math_code_number(index);
1276 break;
1277 case delcode_charcode:
1278 case extdelcode_charcode:
1279 code = tex_get_del_code_number(index);
1280 break;
1281 default:
1282 tex_confusion("scan char");
1283 break;
1284 }
1285 cur_val = code;
1286 cur_val_level = integer_val_level;
1287}
1288
1289
1295
1296static halfword tex_aux_scan_math_style_number(halfword code)
1297{
1298 switch (code) {
1299 case yet_unset_math_style:
1300 return tex_scan_math_style_identifier(0, 0);
1301 case scaled_math_style:
1302 return cur_list.math_scale;
1303 case former_choice_math_style:
1304 return 0;
1305 default:
1306 return code;
1307 }
1308}
1309
1310static void tex_aux_set_cur_val_by_math_style_cmd(halfword code)
1311{
1312 cur_val = tex_aux_scan_math_style_number(code);
1313 cur_val_level = integer_val_level;
1314}
1315
1316
1324
1325
1326
1327static void tex_aux_missing_number_error(void)
1328{
1329 tex_handle_error(
1330 back_error_type,
1331 "Missing number, treated as zero",
1332 "A number should have been here; I inserted '0'. (If you can't figure out why I\n"
1333 "needed to see a number, look up 'weird error' in the index to The TeXbook.)"
1334 );
1335}
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355static int tex_aux_scan_hyph_data_number(halfword code, halfword *target)
1356{
1357 switch (code) {
1358 case prehyphenchar_code:
1359 *target = tex_get_pre_hyphen_char(language_par);
1360 break;
1361 case posthyphenchar_code:
1362 *target = tex_get_post_hyphen_char(language_par);
1363 break;
1364 case preexhyphenchar_code:
1365 *target = tex_get_pre_exhyphen_char(language_par);
1366 break;
1367 case postexhyphenchar_code:
1368 *target = tex_get_post_exhyphen_char(language_par);
1369 break;
1370 case hyphenationmin_code:
1371 *target = tex_get_hyphenation_min(language_par);
1372 break;
1373 case hjcode_code:
1374 *target = tex_get_hj_code(language_par, tex_scan_integer(0, NULL));
1375 break;
1376 default:
1377 return 0;
1378 }
1379 return 1;
1380}
1381
1382static halfword tex_aux_scan_something_internal(halfword cmd, halfword chr, int level, int negative, halfword property)
1383{
1384 int succeeded = 1;
1385 switch (cmd) {
1386
1387 case char_given_cmd:
1388 cur_val = chr;
1389 cur_val_level = integer_val_level;
1390 break;
1391 case some_item_cmd:
1392 {
1393
1397 int save_cur_chr = cur_chr;
1398 cur_chr = chr;
1399 if (tex_aux_set_cur_val_by_some_cmd(chr)) {
1400 succeeded = 2;
1401 } else {
1402 cur_chr = save_cur_chr;
1403 }
1404 break;
1405 }
1406 case internal_toks_cmd:
1407 case register_toks_cmd:
1408 cur_val = eq_value(chr);
1409 cur_val_level = token_val_level;
1410 break;
1411 case internal_integer_cmd:
1412 case register_integer_cmd:
1413 case internal_attribute_cmd:
1414 case register_attribute_cmd:
1415 cur_val = eq_value(chr);
1416 cur_val_level = integer_val_level;
1417 if (level == posit_val_level) {
1418 cur_val = (halfword) tex_posit_to_integer(cur_val);
1419 }
1420 break;
1421 case internal_posit_cmd:
1422 case register_posit_cmd:
1423 cur_val = eq_value(chr);
1424 cur_val_level = posit_val_level;
1425 break;
1426 case internal_dimension_cmd:
1427 case register_dimension_cmd:
1428 cur_val = eq_value(chr);
1429 cur_val_level = dimension_val_level;
1430 if (level == posit_val_level) {
1431 cur_val = tex_posit_to_dimension(cur_val);
1432 }
1433 break;
1434 case internal_glue_cmd:
1435 case register_glue_cmd:
1436 cur_val = eq_value(chr);
1437 cur_val_level = glue_val_level;
1438 break;
1439 case internal_muglue_cmd:
1440 case register_muglue_cmd:
1441 cur_val = eq_value(chr);
1442 cur_val_level = muglue_val_level;
1443 break;
1444 case lua_value_cmd:
1445 tex_aux_set_cur_val_by_lua_value_cmd(chr, property);
1446 if (cur_val_level == no_val_level) {
1447 return 0;
1448 }
1449 break;
1450 case iterator_value_cmd:
1451 cur_val = chr > 0x100000 ? - (chr - 0x100000) : chr;
1452 cur_val_level = integer_val_level;
1453 break;
1454 case math_style_cmd:
1455 tex_aux_set_cur_val_by_math_style_cmd(chr);
1456 break;
1457 case auxiliary_cmd:
1458 tex_aux_set_cur_val_by_auxiliary_cmd(chr);
1459 break;
1460 case page_property_cmd:
1461 tex_aux_set_cur_val_by_page_property_cmd(chr);
1462 break;
1463 case specification_cmd:
1464 tex_aux_set_cur_val_by_specification_cmd(chr);
1465 break;
1466 case define_char_code_cmd:
1467 tex_aux_set_cur_val_by_define_char_cmd(chr);
1468 break;
1469
1470 case define_font_cmd:
1471
1472 if (level == token_val_level) {
1473 cur_val = cur_font_par;
1474 cur_val_level = font_val_level;
1475 return cur_val;
1476 } else {
1477 break;
1478 }
1479 case set_font_cmd:
1480
1481 if (level == token_val_level) {
1482 cur_val = cur_chr;
1483 cur_val_level = font_val_level;
1484 return cur_val;
1485 } else {
1486 break;
1487 }
1488 case define_family_cmd:
1489
1490 {
1491 halfword fam = tex_scan_math_family_number();
1492 cur_val = tex_fam_fnt(fam, chr);
1493 cur_val_level = font_val_level;
1494 return cur_val;
1495 }
1496 case math_parameter_cmd:
1497 {
1498 switch (chr) {
1499 case math_parameter_reset_spacing:
1500 case math_parameter_set_spacing:
1501 case math_parameter_let_spacing:
1502 case math_parameter_copy_spacing:
1503 {
1504 halfword left = tex_scan_math_class_number(0);
1505 halfword right = tex_scan_math_class_number(0);
1506 halfword style = tex_scan_math_style_identifier(0, 0);
1507 halfword node = tex_math_spacing_glue(left, right, style);
1508 cur_val = node ? node : zero_glue;
1509 cur_val_level = muglue_val_level;
1510 break;
1511 }
1512 case math_parameter_set_atom_rule:
1513 case math_parameter_let_atom_rule:
1514 case math_parameter_copy_atom_rule:
1515
1516 case math_parameter_copy_parent:
1517 case math_parameter_set_defaults:
1518 {
1519
1520
1521 break;
1522 }
1523 case math_parameter_let_parent:
1524 {
1525 halfword mathclass = tex_scan_math_class_number(0);
1526 if (valid_math_class_code(mathclass)) {
1527 cur_val = tex_math_has_class_parent(mathclass);
1528 cur_val_level = integer_val_level;
1529 }
1530 break;
1531 }
1532 case math_parameter_set_pre_penalty:
1533 case math_parameter_set_post_penalty:
1534 case math_parameter_set_display_pre_penalty:
1535 case math_parameter_set_display_post_penalty:
1536 {
1537 halfword mathclass = tex_scan_math_class_number(0);
1538 if (valid_math_class_code(mathclass)) {
1539 switch (chr) {
1540 case math_parameter_set_pre_penalty:
1541 cur_val = count_parameter(first_math_pre_penalty_code + mathclass);
1542 break;
1543 case math_parameter_set_post_penalty:
1544 cur_val = count_parameter(first_math_post_penalty_code + mathclass);
1545 break;
1546 case math_parameter_set_display_pre_penalty:
1547 cur_val = count_parameter(first_math_display_pre_penalty_code + mathclass);
1548 break;
1549 case math_parameter_set_display_post_penalty:
1550 cur_val = count_parameter(first_math_display_post_penalty_code + mathclass);
1551 break;
1552 }
1553 } else {
1554 cur_val = 0;
1555 }
1556 cur_val_level = integer_val_level;
1557 break;
1558 }
1559 case math_parameter_ignore:
1560 {
1561 halfword code = tex_scan_math_parameter();
1562 cur_val = code >= 0 ? count_parameter(first_math_ignore_code + code) : 0;
1563 cur_val_level = integer_val_level;
1564 break;
1565 }
1566 case math_parameter_options:
1567 {
1568 halfword mathclass = tex_scan_math_class_number(0);
1569 if (valid_math_class_code(mathclass)) {
1570 cur_val = count_parameter(first_math_options_code + mathclass);
1571 } else {
1572 cur_val = 0;
1573 }
1574 break;
1575 }
1576 default:
1577 {
1578 cur_val = tex_scan_math_style_identifier(0, 0);
1579 switch (math_parameter_value_type(chr)) {
1580 case math_integer_parameter:
1581 cur_val_level = integer_val_level;
1582 break;
1583 case math_dimension_parameter:
1584 cur_val_level = dimension_val_level;
1585 break;
1586 case math_muglue_parameter:
1587 cur_val_level = muglue_val_level;
1588 break;
1589 case math_style_parameter:
1590 cur_val_level = integer_val_level;
1591 break;
1592 }
1593 chr = tex_get_math_parameter(cur_val, chr, NULL);
1594 if (cur_val_level == muglue_val_level) {
1595 switch (chr) {
1596 case petty_muskip_code:
1597 chr = petty_muskip_par;
1598 break;
1599 case tiny_muskip_code:
1600 chr = tiny_muskip_par;
1601 break;
1602 case thin_muskip_code:
1603 chr = thin_muskip_par;
1604 break;
1605 case med_muskip_code:
1606 chr = med_muskip_par;
1607 break;
1608 case thick_muskip_code:
1609 chr = thick_muskip_par;
1610 break;
1611 }
1612 }
1613 cur_val = chr;
1614 break;
1615 }
1616 }
1617 }
1618 break;
1619 case box_property_cmd:
1620 {
1621
1622 halfword n = tex_scan_box_register_number();
1623 halfword b = box_register(n);
1624 switch (chr) {
1625 case box_width_code:
1626 cur_val = b ? box_width(b) : 0;
1627 cur_val_level = dimension_val_level;
1628 break;
1629 case box_height_code:
1630 cur_val = b ? box_height(b) : 0;
1631 cur_val_level = dimension_val_level;
1632 break;
1633 case box_depth_code:
1634 cur_val = b ? box_depth(b) : 0;
1635 cur_val_level = dimension_val_level;
1636 break;
1637 case box_direction_code:
1638 cur_val = b ? box_dir(b) : 0;
1639 cur_val_level = integer_val_level;
1640 break;
1641 case box_geometry_code:
1642 cur_val = b ? box_geometry(b) : 0;
1643 cur_val_level = integer_val_level;
1644 break;
1645 case box_orientation_code:
1646 cur_val = b ? box_orientation(b) : 0;
1647 cur_val_level = integer_val_level;
1648 break;
1649 case box_anchor_code:
1650 case box_anchors_code:
1651 cur_val = b ? box_anchor(b) : 0;
1652 cur_val_level = integer_val_level;
1653 break;
1654 case box_source_code:
1655 cur_val = b ? box_source_anchor(b) : 0;
1656 cur_val_level = integer_val_level;
1657 break;
1658 case box_target_code:
1659 cur_val = b ? box_target_anchor(b) : 0;
1660 cur_val_level = integer_val_level;
1661 break;
1662 case box_xoffset_code:
1663 cur_val = b ? box_x_offset(b) : 0;
1664 cur_val_level = dimension_val_level;
1665 break;
1666 case box_yoffset_code:
1667 cur_val = b ? box_y_offset(b) : 0;
1668 cur_val_level = dimension_val_level;
1669 break;
1670 case box_xmove_code:
1671 cur_val = b ? (box_width(b) - box_x_offset(b)) : 0;
1672 cur_val_level = dimension_val_level;
1673 break;
1674 case box_ymove_code:
1675 cur_val = b ? (box_total(b) - box_y_offset(b)) : 0;
1676 cur_val_level = dimension_val_level;
1677 break;
1678 case box_total_code:
1679 cur_val = b ? box_total(b) : 0;
1680 cur_val_level = dimension_val_level;
1681 break;
1682 case box_shift_code:
1683 cur_val = b ? box_shift_amount(b) : 0;
1684 cur_val_level = dimension_val_level;
1685 break;
1686 case box_adapt_code:
1687 cur_val = 0;
1688 cur_val_level = integer_val_level;
1689 break;
1690 case box_repack_code:
1691 if (node_type(b) == hlist_node) {
1692 cur_val = box_list(b) ? tex_natural_hsize(box_list(b), NULL) : 0;
1693 } else {
1694 cur_val = box_list(b) ? tex_natural_vsize(box_list(b)) : 0;
1695 }
1696 cur_val_level = dimension_val_level;
1697 break;
1698 case box_stretch_code:
1699 cur_val = box_list(b) ? tex_stretch(b) : 0;
1700 cur_val_level = dimension_val_level;
1701 break;
1702 case box_shrink_code:
1703 cur_val = box_list(b) ? tex_shrink(b) : 0;
1704 cur_val_level = dimension_val_level;
1705 break;
1706 case box_freeze_code:
1707 cur_val = node_type(b) == hlist_node ? box_width(b) : box_total(b);
1708 cur_val_level = dimension_val_level;
1709 break;
1710 case box_limitate_code:
1711
1712 cur_val = node_type(b) == hlist_node ? box_width(b) : box_total(b);
1713 cur_val_level = dimension_val_level;
1714 break;
1715 case box_finalize_code:
1716
1717 cur_val = node_type(b) == hlist_node ? box_width(b) : box_total(b);
1718 cur_val_level = dimension_val_level;
1719 break;
1720 case box_limit_code:
1721
1722 cur_val = node_type(b) == hlist_node ? box_width(b) : box_total(b);
1723 cur_val_level = dimension_val_level;
1724 break;
1725 case box_attribute_code:
1726 {
1727 halfword att = tex_scan_attribute_register_number();
1728 cur_val = b ? tex_has_attribute(b, att, unused_attribute_value) : unused_attribute_value;
1729 cur_val_level = integer_val_level;
1730 break;
1731 }
1732 case box_vadjust_code:
1733 cur_val = 0;
1734 if (b) {
1735 if (box_pre_adjusted(b)) {
1736 cur_val |= has_pre_adjust;
1737 }
1738 if (box_post_adjusted(b)) {
1739 cur_val |= has_post_adjust;
1740 }
1741 if (box_pre_migrated(b)) {
1742 cur_val |= has_pre_migrated;
1743 }
1744 if (box_post_migrated(b)) {
1745 cur_val |= has_post_adjust;
1746 }
1747 }
1748 cur_val_level = integer_val_level;
1749 break;
1750 }
1751 break;
1752 }
1753 case font_property_cmd:
1754
1755 {
1756 switch (chr) {
1757 case font_hyphen_code:
1758 {
1759 halfword fnt = tex_scan_font_identifier(NULL);
1760 cur_val = font_hyphen_char(fnt);
1761 cur_val_level = integer_val_level;
1762 break;
1763 }
1764 case font_skew_code:
1765 {
1766 halfword fnt = tex_scan_font_identifier(NULL);
1767 cur_val = font_skew_char(fnt);
1768 cur_val_level = integer_val_level;
1769 break;
1770 }
1771 case font_lp_code:
1772 {
1773 halfword fnt = tex_scan_font_identifier(NULL);
1774 halfword chr = tex_scan_char_number(0);
1775 cur_val = tex_char_lp_from_font(fnt, chr);
1776 cur_val_level = dimension_val_level;
1777 break;
1778 }
1779 case font_rp_code:
1780 {
1781 halfword fnt = tex_scan_font_identifier(NULL);
1782 halfword chr = tex_scan_char_number(0);
1783 cur_val = tex_char_rp_from_font(fnt, chr);
1784 cur_val_level = dimension_val_level;
1785 break;
1786 }
1787 case font_ef_code:
1788 {
1789 halfword fnt = tex_scan_font_identifier(NULL);
1790 halfword chr = tex_scan_char_number(0);
1791 cur_val = tex_char_ef_from_font(fnt, chr);
1792 cur_val_level = integer_val_level;
1793 break;
1794 }
1795 case font_cf_code:
1796 {
1797 halfword fnt = tex_scan_font_identifier(NULL);
1798 halfword chr = tex_scan_char_number(0);
1799 cur_val = tex_char_cf_from_font(fnt, chr);
1800 cur_val_level = integer_val_level;
1801 break;
1802 }
1803 case font_dimension_code:
1804 {
1805 cur_val = tex_get_font_dimension();
1806 cur_val_level = dimension_val_level;
1807 break;
1808 }
1809 case scaled_font_dimension_code:
1810 {
1811 cur_val = tex_get_scaled_font_dimension();
1812 cur_val_level = dimension_val_level;
1813 break;
1814 }
1815 }
1816 break;
1817 }
1818 case register_cmd:
1819
1820 {
1821 switch (chr) {
1822 case integer_val_level:
1823 {
1824 halfword n = tex_scan_integer_register_number();
1825 cur_val = count_register(n);
1826 break;
1827 }
1828 case attribute_val_level:
1829 {
1830 halfword n = tex_scan_attribute_register_number();
1831 cur_val = attribute_register(n);
1832 break;
1833 }
1834 case posit_val_level:
1835 {
1836 halfword n = tex_scan_posit_register_number();
1837 cur_val = posit_register(n);
1838 break;
1839 }
1840 case dimension_val_level:
1841 {
1842 scaled n = tex_scan_dimension_register_number();
1843 cur_val = dimension_register(n);
1844 break;
1845 }
1846 case glue_val_level:
1847 {
1848 halfword n = tex_scan_glue_register_number();
1849 cur_val = skip_register(n);
1850 break;
1851 }
1852 case muglue_val_level:
1853 {
1854 halfword n = tex_scan_muglue_register_number();
1855 cur_val = muskip_register(n);
1856 break;
1857 }
1858 case token_val_level:
1859 {
1860 halfword n = tex_scan_toks_register_number();
1861 cur_val = toks_register(n);
1862 break;
1863 }
1864 }
1865 cur_val_level = chr;
1866 break;
1867 }
1868 case ignore_something_cmd:
1869 break;
1870 case hyphenation_cmd:
1871 if (tex_aux_scan_hyph_data_number(chr, &cur_val)) {
1872 cur_val_level = integer_val_level;
1873 break;
1874 } else {
1875 goto DEFAULT;
1876 }
1877 case integer_cmd:
1878 case index_cmd:
1879 cur_val = chr;
1880 cur_val_level = integer_val_level;
1881 break;
1882 case dimension_cmd:
1883 cur_val = chr;
1884 cur_val_level = dimension_val_level;
1885 break;
1886 case posit_cmd:
1887 cur_val = chr;
1888 cur_val_level = posit_val_level;
1889 break;
1890 case gluespec_cmd:
1891 cur_val = chr;
1892 cur_val_level = glue_val_level;
1893 break;
1894 case mugluespec_cmd:
1895 cur_val = chr;
1896 cur_val_level = muglue_val_level;
1897 break;
1898 case mathspec_cmd:
1899 cur_val = chr;
1900 if (chr) {
1901 switch (node_subtype(chr)) {
1902 case tex_mathcode:
1903 cur_val = math_spec_value(chr);
1904 cur_val_level = integer_val_level;
1905 break;
1906 case umath_mathcode:
1907
1908 case mathspec_mathcode:
1909 cur_val_level = mathspec_val_level;
1910 break;
1911 default:
1912 cur_val = 0;
1913 cur_val_level = integer_val_level;
1914 break;
1915 }
1916 } else {
1917 cur_val_level = integer_val_level;
1918 }
1919 break;
1920 case fontspec_cmd:
1921 cur_val = tex_get_font_identifier(chr) ? chr : null;
1922 cur_val_level = fontspec_val_level;
1923 break;
1924 case association_cmd:
1925 switch (chr) {
1926 case unit_association_code:
1927 cur_val = tex_get_unit_class(tex_scan_unit_register_number(0));
1928 cur_val_level = integer_val_level;
1929 break;
1930 }
1931 break;
1932 case begin_paragraph_cmd:
1933 switch (chr) {
1934 case snapshot_par_code:
1935 {
1936 halfword par = tex_find_par_par(cur_list.head);
1937 cur_val = par ? par_state(par) : 0;
1938 cur_val_level = integer_val_level;
1939 break;
1940 }
1941
1942 case wrapup_par_code:
1943 {
1944 halfword par = tex_find_par_par(cur_list.head);
1945 cur_val = par ? par_end_par_tokens(par) : null;
1946 cur_val_level = token_val_level;
1947 break;
1948 }
1949 default:
1950 goto DEFAULT;
1951 }
1952 break;
1953
1969
1972 case parameter_cmd:
1973 tex_get_x_token();
1974 if (valid_iterator_reference(cur_tok)) {
1975 cur_val = tex_expand_iterator(cur_tok);
1976 cur_val_level = integer_val_level;
1977 break;
1978 } else {
1979 goto DEFAULT;
1980 }
1981 case interaction_cmd:
1982 cur_val = cur_chr;
1983 cur_val_level = integer_val_level;
1984 break;
1985 default:
1986 DEFAULT:
1987
1988 tex_handle_error(
1989 normal_error_type,
1990 "You can't use '%C' after \\the",
1991 cmd, chr,
1992 "I'm forgetting what you said and using zero instead."
1993 );
1994 cur_val = 0;
1995 cur_val_level = (level == token_val_level) ? integer_val_level : dimension_val_level;
1996 break;
1997 }
1998 tex_aux_downgrade_cur_val(level, succeeded, negative);
1999 return cur_val;
2000}
2001
2002void tex_scan_something_simple(halfword cmd, halfword chr)
2003{
2004 if (cmd >= min_internal_cmd && cmd <= max_internal_cmd) {
2005 tex_aux_scan_something_internal(cmd, chr, no_val_level, 0, 0);
2006 } else {
2007
2008
2009
2010
2011
2012
2013 cur_val = 0;
2014 cur_val_level = integer_val_level;
2015 }
2016}
2017
2018
2028
2029inline static halfword tex_aux_scan_limited_int(int optional_equal, int min, int max, const char *invalid)
2030{
2031 halfword v = tex_scan_integer(optional_equal, NULL);
2032 if (v < min || v > max) {
2033 tex_handle_error(
2034 normal_error_type,
2035 "%s (%i) should be in the range %i..%i",
2036 invalid, v, min, max,
2037 "I'm going to use 0 instead of that illegal code value."
2038 );
2039 return 0;
2040 } else {
2041 return v;
2042 }
2043}
2044
2045halfword tex_scan_integer_register_number (void) { return tex_aux_scan_limited_int(0, 0, max_integer_register_index, "Integer register index"); }
2046halfword tex_scan_dimension_register_number (void) { return tex_aux_scan_limited_int(0, 0, max_dimension_register_index, "Dimension register index"); }
2047halfword tex_scan_attribute_register_number (void) { return tex_aux_scan_limited_int(0, 0, max_attribute_register_index, "Attribute register index"); }
2048halfword tex_scan_posit_register_number (void) { return tex_aux_scan_limited_int(0, 0, max_posit_register_index, "Posit register index"); }
2049halfword tex_scan_glue_register_number (void) { return tex_aux_scan_limited_int(0, 0, max_glue_register_index, "Glue register index"); }
2050halfword tex_scan_muglue_register_number (void) { return tex_aux_scan_limited_int(0, 0, max_muglue_register_index, "Muglue register index"); }
2051halfword tex_scan_toks_register_number (void) { return tex_aux_scan_limited_int(0, 0, max_toks_register_index, "Toks register index"); }
2052halfword tex_scan_box_register_number (void) { return tex_aux_scan_limited_int(0, 0, max_box_register_index, "Box register index"); }
2053halfword tex_scan_unit_register_number (int optional_equal) { return tex_aux_scan_limited_int(optional_equal, 0, max_unit_register_index, "Unit register index"); }
2054halfword tex_scan_mark_number (void) { return tex_aux_scan_limited_int(0, 0, max_mark_index, "Marks index"); }
2055halfword tex_scan_char_number (int optional_equal) { return tex_aux_scan_limited_int(optional_equal, 0, max_character_code, "Character code"); }
2056halfword tex_scan_math_char_number (void) { return tex_aux_scan_limited_int(0, 0, max_math_character_code, "Character code"); }
2057halfword tex_scan_math_family_number (void) { return tex_aux_scan_limited_int(0, 0, max_math_family_index, "Math family"); }
2058halfword tex_scan_math_properties_number (void) { return tex_aux_scan_limited_int(0, 0, max_math_property, "Math properties"); }
2059halfword tex_scan_math_group_number (void) { return tex_aux_scan_limited_int(0, 0, max_math_group, "Math group"); }
2060halfword tex_scan_math_index_number (void) { return tex_aux_scan_limited_int(0, 0, max_math_index, "Math index"); }
2061halfword tex_scan_math_discretionary_number (int optional_equal) { return tex_aux_scan_limited_int(optional_equal, 0, max_math_discretionary, "Math discretionary"); }
2062singleword tex_scan_box_index (void) { return (singleword) tex_aux_scan_limited_int(0, 0, max_box_index, "Box index"); }
2063singleword tex_scan_box_axis (void) { return (singleword) tex_aux_scan_limited_int(0, 0, max_box_axis, "Box axis"); }
2064halfword tex_scan_category_code (int optional_equal) { return tex_aux_scan_limited_int(optional_equal, 0, max_category_code,"Category code"); }
2065halfword tex_scan_space_factor (int optional_equal) { return tex_aux_scan_limited_int(optional_equal, min_space_factor, max_space_factor, "Space factor"); }
2066halfword tex_scan_scale_factor (int optional_equal) { return tex_aux_scan_limited_int(optional_equal, min_scale_factor, max_scale_factor, "Scale factor"); }
2067halfword tex_scan_function_reference (int optional_equal) { return tex_aux_scan_limited_int(optional_equal, 0, max_function_reference, "Function reference"); }
2068halfword tex_scan_bytecode_reference (int optional_equal) { return tex_aux_scan_limited_int(optional_equal, 0, max_bytecode_index, "Bytecode reference"); }
2069halfword tex_scan_limited_scale (int optional_equal) { return tex_aux_scan_limited_int(optional_equal, -max_limited_scale, max_limited_scale, "Limited scale"); }
2070halfword tex_scan_positive_scale (int optional_equal) { return tex_aux_scan_limited_int(optional_equal, min_limited_scale, max_limited_scale, "Limited scale"); }
2071halfword tex_scan_positive_number (int optional_equal) { return tex_aux_scan_limited_int(optional_equal, 0, max_integer, "Positive number"); }
2072halfword tex_scan_parameter_index (void) { return tex_aux_scan_limited_int(0, 0, 15, "Parameter index"); }
2073
2074halfword tex_scan_math_class_number(int optional_equal)
2075{
2076 halfword v = tex_aux_scan_limited_int(optional_equal, -1, max_math_class_code + 1, "Math class");
2077 if (v >= 0 && v <= max_math_class_code) {
2078 return v;
2079 } else {
2080 return unset_noad_class;
2081 }
2082}
2083
2084
2100
2101static void tex_aux_number_to_big_error(void)
2102{
2103 tex_handle_error(
2104 normal_error_type,
2105 "Number too big",
2106 "I can only go up to 2147483647 = '17777777777 = \"7FFFFFFF, so I'm using that\n"
2107 "number instead of yours."
2108 );
2109}
2110
2111static void tex_aux_improper_constant_error(void)
2112{
2113 tex_handle_error(
2114 back_error_type,
2115 "Improper alphabetic constant",
2116 "A one-character control sequence belongs after a ` mark. So I'm essentially\n"
2117 "inserting \\0 here."
2118 );
2119}
2120
2121
2134
2135
2136static void tex_aux_scan_integer_no_number()
2137{
2138
2139 if (lmt_error_state.intercept) {
2140 lmt_error_state.last_intercept = 1 ;
2141 if (cur_cmd != spacer_cmd) {
2142 tex_back_input(cur_tok);
2143 }
2144 } else {
2145 tex_aux_missing_number_error();
2146 }
2147}
2148
2149halfword tex_scan_integer(int optional_equal, int *radix)
2150{
2151 bool negative = false;
2152 long long result = 0;
2153 while (1) {
2154 tex_get_x_token();
2155 if (cur_cmd == spacer_cmd) {
2156 continue;
2157 } else if (cur_tok == equal_token) {
2158 if (optional_equal) {
2159 optional_equal = 0;
2160 continue;
2161 } else {
2162 break;
2163 }
2164 } else if (cur_tok == minus_token) {
2165 negative = ! negative;
2166 } else if (cur_tok != plus_token) {
2167 break;
2168 }
2169 };
2170 if (cur_tok == alpha_token) {
2171
2176 tex_get_token();
2177 if (cur_tok < cs_token_flag) {
2178 result = cur_chr;
2179 if (cur_cmd == right_brace_cmd) {
2180 ++lmt_input_state.align_state;
2181
2182 } else if (cur_cmd == left_brace_cmd || cur_cmd == relax_cmd) {
2183
2184 --lmt_input_state.align_state;
2185 }
2186 } else {
2187
2191 strnumber txt = cs_text(cur_tok - cs_token_flag);
2192 if (tex_single_letter(txt)) {
2193 result = aux_str2uni(str_string(txt));
2194 } else if (tex_is_active_cs(txt)) {
2195 result = active_cs_value(txt);
2196 } else {
2197 result = max_character_code + 1;
2198 }
2199 }
2200 if (result > max_character_code) {
2201 if (lmt_error_state.intercept) {
2202 lmt_error_state.last_intercept = 1;
2203 tex_back_input(cur_tok);
2204 } else {
2205 tex_aux_improper_constant_error();
2206 return 0;
2207 }
2208 } else {
2209
2210 tex_get_x_token();
2211 if (cur_cmd != spacer_cmd) {
2212 tex_back_input(cur_tok);
2213 }
2214 }
2215 } else if ((cur_cmd >= min_internal_cmd && cur_cmd <= max_internal_cmd) || cur_cmd == parameter_cmd) {
2216 result = tex_aux_scan_something_internal(cur_cmd, cur_chr, integer_val_level, 0, 0);
2217 if (cur_val_level != integer_val_level) {
2218 tex_aux_scan_integer_no_number();
2219 return 0;
2220 }
2221 } else {
2222
2223 bool vacuous = true;
2224 bool ok_so_far = true;
2225
2228 switch (cur_tok) {
2229 case octal_token:
2230 {
2231 if (radix) {
2232 *radix = 8;
2233 }
2234 while (1) {
2235 unsigned d = 0;
2236 tex_get_x_token();
2237 if ((cur_tok >= zero_token) && (cur_tok <= seven_token)) {
2238 d = cur_tok - zero_token;
2239 } else {
2240 goto DONE;
2241 }
2242 vacuous = false;
2243 if (ok_so_far) {
2244 result = result * 8 + d;
2245 if (result > max_integer) {
2246 result = max_integer;
2247 if (lmt_error_state.intercept) {
2248 vacuous = true;
2249 goto DONE;
2250 } else {
2251 tex_aux_number_to_big_error();
2252 }
2253 ok_so_far = 0;
2254 }
2255 }
2256 }
2257
2258 }
2259 case hex_token:
2260 {
2261 if (radix) {
2262 *radix = 16;
2263 }
2264 while (1) {
2265 unsigned d = 0;
2266 tex_get_x_token();
2267 if ((cur_tok >= zero_token) && (cur_tok <= nine_token)) {
2268 d = cur_tok - zero_token;
2269 } else if ((cur_tok >= A_token_l) && (cur_tok <= F_token_l)) {
2270 d = cur_tok - A_token_l + 10;
2271 } else if ((cur_tok >= A_token_o) && (cur_tok <= F_token_o)) {
2272 d = cur_tok - A_token_o + 10;
2273 } else {
2274 goto DONE;
2275 }
2276 vacuous = false;
2277 if (ok_so_far) {
2278 result = result * 16 + d;
2279 if (result > max_integer) {
2280 result = max_integer;
2281 if (lmt_error_state.intercept) {
2282 vacuous = true;
2283 goto DONE;
2284 } else {
2285 tex_aux_number_to_big_error();
2286 }
2287 ok_so_far = false;
2288 }
2289 }
2290 }
2291
2292 }
2293 default:
2294 if (radix) {
2295 *radix = 10;
2296 }
2297 while (1) {
2298 unsigned d = 0;
2299 if ((cur_tok >= zero_token) && (cur_tok <= nine_token)) {
2300 d = cur_tok - zero_token;
2301 } else {
2302 goto DONE;
2303 }
2304 vacuous = false;
2305 if (ok_so_far) {
2306 result = result * 10 + d;
2307 if (result > max_integer) {
2308 result = max_integer;
2309 if (lmt_error_state.intercept) {
2310 vacuous = true;
2311 goto DONE;
2312 } else {
2313 tex_aux_number_to_big_error();
2314 }
2315 ok_so_far = false;
2316 }
2317 }
2318 tex_get_x_token();
2319 }
2320
2321 }
2322 DONE:
2323 if (vacuous) {
2324 tex_aux_scan_integer_no_number();
2325 } else {
2326 tex_push_back(cur_tok, cur_cmd, cur_chr);
2327 }
2328 }
2329
2330 cur_val = (halfword) (negative ? - result : result);
2331 return cur_val;
2332}
2333
2334void tex_scan_integer_validate(void)
2335{
2336 while (1) {
2337 tex_get_x_token();
2338 if (cur_cmd == spacer_cmd || cur_tok == minus_token) {
2339 continue;
2340 } else if (cur_tok != plus_token) {
2341 break;
2342 }
2343 };
2344 if (cur_tok == alpha_token) {
2345 long long result = 0;
2346 tex_get_token();
2347 if (cur_tok < cs_token_flag) {
2348 result = cur_chr;
2349
2350 if (cur_cmd == right_brace_cmd) {
2351 ++lmt_input_state.align_state;
2352 } else if (cur_cmd == left_brace_cmd || cur_cmd == relax_cmd) {
2353 --lmt_input_state.align_state;
2354 }
2355 } else {
2356 strnumber txt = cs_text(cur_tok - cs_token_flag);
2357 if (tex_single_letter(txt)) {
2358 result = aux_str2uni(str_string(txt));
2359 } else if (tex_is_active_cs(txt)) {
2360 result = active_cs_value(txt);
2361 } else {
2362 result = max_character_code + 1;
2363 }
2364 }
2365 if (result > max_character_code) {
2366 if (lmt_error_state.intercept) {
2367 lmt_error_state.last_intercept = 1;
2368 tex_back_input(cur_tok);
2369 } else {
2370 tex_aux_improper_constant_error();
2371 }
2372 } else {
2373 tex_get_x_token();
2374 if (cur_cmd != spacer_cmd) {
2375 tex_back_input(cur_tok);
2376 }
2377 }
2378 } else if ((cur_cmd >= min_internal_cmd && cur_cmd <= max_internal_cmd) || cur_cmd == parameter_cmd) {
2379 tex_aux_scan_something_internal(cur_cmd, cur_chr, integer_val_level, 0, 0);
2380 if (cur_val_level != integer_val_level) {
2381 tex_aux_scan_integer_no_number();
2382 }
2383 } else {
2384 bool vacuous = true;
2385 switch (cur_tok) {
2386 case octal_token:
2387 while (1) {
2388 tex_get_x_token();
2389 if (! (cur_tok >= zero_token && cur_tok <= seven_token)) {
2390 goto DONE;
2391 }
2392 vacuous = false;
2393 }
2394 case hex_token:
2395 while (1) {
2396 tex_get_x_token();
2397 if (! ((cur_tok >= zero_token && cur_tok <= nine_token) ||
2398 (cur_tok >= A_token_l && cur_tok <= F_token_l ) ||
2399 (cur_tok >= A_token_o && cur_tok <= F_token_o ) )) {
2400 goto DONE;
2401 }
2402 vacuous = false;
2403 }
2404 default:
2405 while (1) {
2406 if (! (cur_tok >= zero_token && cur_tok <= nine_token)) {
2407 goto DONE;
2408 }
2409 vacuous = false;
2410 tex_get_x_token();
2411 }
2412 }
2413 DONE:
2414 if (vacuous) {
2415 tex_aux_scan_integer_no_number();
2416 } else {
2417 tex_push_back(cur_tok, cur_cmd, cur_chr);
2418 }
2419 }
2420}
2421
2422int tex_scan_cardinal(int optional_equal, unsigned *value, int dontbark)
2423{
2424 long long result = 0;
2425
2426
2427
2428 while (1) {
2429 tex_get_x_token();
2430 if (cur_cmd != spacer_cmd) {
2431 if (optional_equal && (cur_tok == equal_token)) {
2432 optional_equal = 0;
2433 } else {
2434 break;
2435 }
2436 }
2437 }
2438 if (cur_cmd >= min_internal_cmd && cur_cmd <= max_internal_cmd) {
2439 result = tex_aux_scan_something_internal(cur_cmd, cur_chr, integer_val_level, 0, 0);
2440 } else {
2441 bool vacuous = true;
2442 switch (cur_tok) {
2443 case octal_token:
2444 {
2445 while (1) {
2446 unsigned d = 0;
2447 tex_get_x_token();
2448 if ((cur_tok >= zero_token) && (cur_tok <= seven_token)) {
2449 d = cur_tok - zero_token;
2450 } else {
2451 goto DONE;
2452 }
2453 vacuous = false;
2454 result = result * 8 + d;
2455 if (result > max_cardinal) {
2456 result = max_cardinal;
2457 }
2458 }
2459
2460 }
2461 case hex_token:
2462 {
2463 while (1) {
2464 unsigned d = 0;
2465 tex_get_x_token();
2466 if ((cur_tok >= zero_token) && (cur_tok <= nine_token)) {
2467 d = cur_tok - zero_token;
2468 } else if ((cur_tok >= A_token_l) && (cur_tok <= F_token_l)) {
2469 d = cur_tok - A_token_l + 10;
2470 } else if ((cur_tok >= A_token_o) && (cur_tok <= F_token_o)) {
2471 d = cur_tok - A_token_o + 10;
2472 } else {
2473 goto DONE;
2474 }
2475 vacuous = false;
2476 result = result * 16 + d;
2477 if (result > max_cardinal) {
2478 result = max_cardinal;
2479 }
2480 }
2481
2482 }
2483 default:
2484 {
2485 while (1) {
2486 unsigned d = 0;
2487 if ((cur_tok >= zero_token) && (cur_tok <= nine_token)) {
2488 d = cur_tok - zero_token;
2489 } else {
2490 goto DONE;
2491 }
2492 vacuous = false;
2493 result = result * 10 + d;
2494 if (result > max_cardinal) {
2495 result = max_cardinal;
2496 }
2497 tex_get_x_token();
2498 }
2499
2500 }
2501 }
2502 DONE:
2503 if (vacuous) {
2504 if (dontbark) {
2505 return 0;
2506 } else {
2507 tex_aux_missing_number_error();
2508 }
2509 } else {
2510 tex_push_back(cur_tok, cur_cmd, cur_chr);
2511 }
2512 }
2513 *value = (unsigned) result;
2514 cur_val = (halfword) result;
2515 return 1;
2516}
2517
2518
2524
2525static halfword tex_aux_coerced_glue(halfword value, halfword level)
2526{
2527 if (level == glue_val_level || level == muglue_val_level) {
2528 int v = glue_amount(value);
2529 tex_flush_node(value);
2530 return v;
2531 } else {
2532 return value;
2533 }
2534}
2535
2536
2571
2572static void tex_aux_scan_dimension_mu_error(void) {
2573 tex_handle_error(
2574 normal_error_type,
2575 "Illegal unit of measure (mu inserted)",
2576 "The unit of measurement in math glue must be mu." );
2577
2578}
2579
2580static void tex_aux_scan_dimension_fi_error(void) {
2581 tex_handle_error(
2582 normal_error_type,
2583 "Illegal unit of measure",
2584 "The unit of measurement can't be fi, fil, fill or filll here." );
2585
2586}
2587
2588static void tex_aux_scan_dimension_unknown_unit_error(void) {
2589 tex_handle_error(
2590 normal_error_type,
2591 "Illegal unit of measure (pt inserted)",
2592 "Dimensions can be in units of em, ex, sp, cm, mm, es, ts, pt, bp, dk, pc, dd\n"
2593 "cc or in; but yours is a new one! I'll assume that you meant to say pt, for\n"
2594 "printer's points: two letters."
2595 );
2596}
2597
2598
2604
2605static void tex_aux_scan_dimension_out_of_range_error(void) {
2606 tex_handle_error(
2607 normal_error_type,
2608 "Dimension too large",
2609 "I can't work with sizes bigger than about 19 feet (45 Theodores as of 2023),\n"
2610 "575 centimeters, 2300 Toves, 230 Ediths or 16383 points. Continue and I'll use\n"
2611 "the largest value I can."
2612 );
2613}
2614
2615# define set_conversion(A,B) do { num=(A); denom=(B); } while(0)
2616
2617
2626
2627typedef enum scanned_unit {
2628 no_unit_scanned,
2629 normal_unit_scanned,
2630 scaled_point_scanned,
2631 relative_unit_scanned,
2632 math_unit_scanned,
2633 flexible_unit_scanned,
2634 quantitity_unit_scanned,
2635} scanned_unit;
2636
2637
2666
2667
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2858
2859
2865
2866# define unit_hashes(a,b,c,d) \
2867 unit_parameter_hash(a,c): \
2868 case unit_parameter_hash(b,d): \
2869 case unit_parameter_hash(a,d): \
2870 case unit_parameter_hash(b,c)
2871
2872int tex_valid_userunit(halfword cmd, halfword chr, halfword cs)
2873{
2874 (void) cs;
2875 switch (cmd) {
2876 case call_cmd:
2877 case protected_call_cmd:
2878 case semi_protected_call_cmd:
2879 case constant_call_cmd:
2880 return chr && ! get_token_preamble(chr);
2881 case internal_dimension_cmd:
2882 case register_dimension_cmd:
2883 case dimension_cmd:
2884 case lua_value_cmd:
2885 return 1;
2886 default:
2887 return 0;
2888 }
2889}
2890
2891int tex_get_unit_class(halfword index)
2892{
2893 halfword class = unit_parameter(index);
2894 return class < 0 ? - class : class ? user_unit_class : unset_unit_class;
2895}
2896
2897int tex_get_userunit(halfword index, scaled *value)
2898{
2899 halfword cs = unit_parameter(index);
2900 if (cs > 0) {
2901 halfword cmd = eq_type(cs);
2902 halfword chr = eq_value(cs);
2903 switch (cmd) {
2904 case internal_dimension_cmd:
2905 case register_dimension_cmd:
2906 *value = eq_value(chr);
2907 return relative_unit_scanned;
2908 case dimension_cmd:
2909 *value = chr;
2910 return relative_unit_scanned;
2911 case call_cmd:
2912 case protected_call_cmd:
2913 case semi_protected_call_cmd:
2914 case constant_call_cmd:
2915 if (chr && ! get_token_preamble(chr)) {
2916 halfword list = token_link(chr);
2917 tex_begin_associated_list(list);
2918 tex_aux_scan_expr(dimension_val_level);
2919 if (cur_val_level == dimension_val_level) {
2920 *value = cur_val;
2921 return 1;
2922 }
2923 }
2924
2925 *value = 0;
2926 return 1;
2927 case lua_value_cmd:
2928
2929 tex_aux_set_cur_val_by_lua_value_cmd(chr, index);
2930 if (cur_val_level == dimension_val_level) {
2931 *value = cur_val;
2932 return 1;
2933 }
2934 }
2935 }
2936
2937 *value = 0;
2938 return 0;
2939}
2940
2941void tex_initialize_units(void)
2942{
2943 unit_parameter(unit_parameter_hash('p','t')) = - tex_unit_class;
2944 unit_parameter(unit_parameter_hash('c','m')) = - tex_unit_class;
2945 unit_parameter(unit_parameter_hash('m','m')) = - tex_unit_class;
2946 unit_parameter(unit_parameter_hash('e','m')) = - tex_unit_class;
2947 unit_parameter(unit_parameter_hash('e','x')) = - tex_unit_class;
2948 unit_parameter(unit_parameter_hash('s','p')) = - tex_unit_class;
2949 unit_parameter(unit_parameter_hash('b','p')) = - tex_unit_class;
2950 unit_parameter(unit_parameter_hash('f','i')) = - tex_unit_class;
2951 unit_parameter(unit_parameter_hash('t','s')) = - luametatex_unit_class;
2952 unit_parameter(unit_parameter_hash('e','s')) = - luametatex_unit_class;
2953 unit_parameter(unit_parameter_hash('e','u')) = - luametatex_unit_class;
2954 unit_parameter(unit_parameter_hash('d','k')) = - luametatex_unit_class;
2955 unit_parameter(unit_parameter_hash('m','u')) = - tex_unit_class;
2956 unit_parameter(unit_parameter_hash('d','d')) = - tex_unit_class;
2957 unit_parameter(unit_parameter_hash('c','c')) = - tex_unit_class;
2958 unit_parameter(unit_parameter_hash('p','c')) = - tex_unit_class;
2959 unit_parameter(unit_parameter_hash('p','x')) = - pdftex_unit_class;
2960 unit_parameter(unit_parameter_hash('i','n')) = - tex_unit_class;
2961}
2962
2963static int tex_aux_scan_unit(halfword *num, halfword *denom, halfword *value, halfword *order)
2964{
2965
2966 do {
2967 tex_get_x_token();
2968 } while (cur_cmd == spacer_cmd);
2969 if (cur_cmd >= min_internal_cmd && cur_cmd <= max_internal_cmd) {
2970 return quantitity_unit_scanned;
2971 } else {
2972 int chrone, chrtwo, index;
2973 halfword tokone, toktwo;
2974 halfword save_cur_cs = cur_cs;
2975 tokone = cur_tok;
2976 if (cur_cmd == letter_cmd || cur_cmd == other_char_cmd) {
2977 chrone = cur_chr;
2978 } else {
2979 goto BACK_ONE;
2980 }
2981 tex_get_x_token();
2982 toktwo = cur_tok;
2983 if (cur_cmd == letter_cmd || cur_cmd == other_char_cmd) {
2984 chrtwo = cur_chr;
2985 } else {
2986 goto BACK_TWO;
2987 }
2988 cur_cs = save_cur_cs;
2989 index = unit_parameter_index(chrone, chrtwo);
2990 if (index >= 0) {
2991 switch (index) {
2992 case unit_hashes('p','P','t','T'):
2993 return normal_unit_scanned;
2994 case unit_hashes('c','C','m','M'):
2995 *num = 7227;
2996 *denom = 254;
2997 return normal_unit_scanned;
2998 case unit_hashes('m','M','m','M'):
2999 *num = 7227;
3000 *denom = 2540;
3001 return normal_unit_scanned;
3002 case unit_hashes('e','E','m','M'):
3003 *value = tex_get_scaled_em_width(cur_font_par);
3004 return relative_unit_scanned;
3005 case unit_hashes('e','E','x','X'):
3006 *value = tex_get_scaled_ex_height(cur_font_par);
3007 return relative_unit_scanned;
3008 case unit_hashes('s','S','p','P'):
3009 return scaled_point_scanned;
3010 case unit_hashes('b','B','p','P'):
3011 *num = 7227;
3012 *denom = 7200;
3013 return normal_unit_scanned;
3014 case unit_hashes('f','F','i','I'):
3015 if (order) {
3016 *order = fi_glue_order;
3017 if (tex_scan_character("lL", 0, 0, 0)) {
3018 *order = fil_glue_order;
3019 if (tex_scan_character("lL", 0, 0, 0)) {
3020 *order = fill_glue_order;
3021 if (tex_scan_character("lL", 0, 0, 0)) {
3022 *order = filll_glue_order;
3023 }
3024 }
3025 }
3026 return flexible_unit_scanned;
3027 }
3028 break;
3029 case unit_hashes('t','T','s','S'):
3030 *num = 4588;
3031 *denom = 645;
3032 return normal_unit_scanned;
3033 case unit_hashes('e','E','s','S'):
3034 *num = 9176;
3035 *denom = 129;
3036 return normal_unit_scanned;
3037 case unit_hashes('e','E','u','U'):
3038 *num = 9176 * eu_factor_par;
3039 *denom = 129 * 10;
3040 return normal_unit_scanned;
3041 case unit_hashes('d','D','k','K'):
3042 *num = 49838;
3043 *denom = 7739;
3044 return normal_unit_scanned;
3045 case unit_hashes('m','M','u','U'):
3046 if (order) {
3047 return math_unit_scanned;
3048 } else {
3049 break;
3050 }
3051 case unit_hashes('d','D','d','D'):
3052 *num = 1238;
3053 *denom = 1157;
3054 return normal_unit_scanned;
3055 case unit_hashes('c','C','c','C'):
3056 *num = 14856;
3057 *denom = 1157;
3058 return normal_unit_scanned;
3059 case unit_hashes('p','P','c','C'):
3060 *num = 12;
3061 *denom = 1;
3062 return normal_unit_scanned;
3063 case unit_hashes('p','P','x','X'):
3064 *value = px_dimension_par;
3065 return relative_unit_scanned;
3066 case unit_hashes('i','I','n','N'):
3067 *num = 7227;
3068 *denom = 100;
3069 return normal_unit_scanned;
3070
3071
3072
3073
3074
3075
3076
3077
3078 default:
3079 if (tex_get_userunit(index, value)) {
3080 return relative_unit_scanned;
3081 }
3082 }
3083 }
3084 BACK_TWO:
3085 tex_back_input(toktwo);
3086 BACK_ONE:
3087 tex_back_input(tokone);
3088 cur_cs = save_cur_cs;
3089 return no_unit_scanned;
3090 }
3091}
3092
3093
3101
3102halfword tex_scan_dimension(int mu, int inf, int shortcut, int optional_equal, halfword *order)
3103{
3104 bool negative = false;
3105 int fraction = 0;
3106 int num = 0;
3107 int denom = 0;
3108 scaled v;
3109 int save_cur_val;
3110 halfword cur_order = normal_glue_order;
3111 lmt_scanner_state.arithmic_error = 0;
3112 if (! shortcut) {
3113 while (1) {
3114 tex_get_x_token();
3115 if (cur_cmd == spacer_cmd) {
3116 continue;
3117 } else if (cur_tok == equal_token) {
3118 if (optional_equal) {
3119 optional_equal = 0;
3120 continue;
3121 } else {
3122 break;
3123 }
3124 } else if (cur_tok == minus_token) {
3125 negative = ! negative;
3126 } else if (cur_tok != plus_token) {
3127 break;
3128 }
3129 }
3130 if (cur_cmd >= min_internal_cmd && cur_cmd <= max_internal_cmd) {
3131 cur_val = tex_aux_scan_something_internal(cur_cmd, cur_chr, mu ? muglue_val_level : dimension_val_level, 0, 0);
3132 if (mu) {
3133 cur_val = tex_aux_coerced_glue(cur_val, cur_val_level);
3134 if (cur_val_level == muglue_val_level) {
3135 goto ATTACH_SIGN;
3136 } else if (cur_val_level != integer_val_level) {
3137 tex_aux_mu_error(2);
3138 }
3139 } else if (cur_val_level == dimension_val_level) {
3140 goto ATTACH_SIGN;
3141 } else if (cur_val_level == posit_val_level) {
3142 cur_val = tex_posit_to_dimension(cur_val);
3143 goto ATTACH_SIGN;
3144 }
3145 } else {
3146 int has_fraction = tex_token_is_seperator(cur_tok);
3147 if (has_fraction) {
3148 cur_val = 0;
3149 } else {
3150 int cur_radix;
3151 tex_back_input(cur_tok);
3152 cur_val = tex_scan_integer(0, &cur_radix);
3153 if (cur_radix == 10 && tex_token_is_seperator(cur_tok)) {
3154 has_fraction = 1;
3155 tex_get_token();
3156 }
3157 }
3158 if (has_fraction) {
3159 unsigned k = 0;
3160 unsigned char digits[18];
3161 while (1) {
3162 tex_get_x_token();
3163 if ((cur_tok > nine_token) || (cur_tok < zero_token)) {
3164 break;
3165 } else if (k < 17) {
3166 digits[k] = (unsigned char) (cur_tok - zero_token);
3167 ++k;
3168 }
3169 }
3170 fraction = tex_round_decimals_digits(digits, k);
3171 if (cur_cmd != spacer_cmd) {
3172 tex_back_input(cur_tok);
3173 }
3174 }
3175 }
3176 } else {
3177
3178 }
3179 if (cur_val < 0) {
3180 negative = ! negative;
3181 cur_val = -cur_val;
3182 }
3183 save_cur_val = cur_val;
3184
3188 if (! lmt_error_state.last_intercept) {
3189 switch (tex_aux_scan_unit(&num, &denom, &v, &cur_order)) {
3190 case no_unit_scanned:
3191
3192 if (lmt_error_state.intercept) {
3193 lmt_error_state.last_intercept = 1;
3194 } else {
3195 tex_aux_scan_dimension_unknown_unit_error();
3196 }
3197 goto ATTACH_FRACTION;
3198 case normal_unit_scanned:
3199
3200 if (mu) {
3201 tex_aux_scan_dimension_unknown_unit_error();
3202 } else if (num) {
3203 int remainder = 0;
3204 cur_val = tex_xn_over_d_r(cur_val, num, denom, &remainder);
3205 fraction = (num * fraction + 0200000 * remainder) / denom;
3206 cur_val += fraction / 0200000;
3207 fraction = fraction % 0200000;
3208 }
3209 goto ATTACH_FRACTION;
3210 case scaled_point_scanned:
3211
3212 if (mu) {
3213 tex_aux_scan_dimension_unknown_unit_error();
3214 }
3215 goto DONE;
3216 case relative_unit_scanned:
3217
3218 if (mu) {
3219 tex_aux_scan_dimension_unknown_unit_error();
3220 }
3221 cur_val = tex_nx_plus_y(save_cur_val, v, tex_xn_over_d(v, fraction, 0200000));
3222 goto DONE;
3223 case math_unit_scanned:
3224
3225 if (! mu) {
3226 tex_aux_scan_dimension_mu_error();
3227 }
3228 goto ATTACH_FRACTION;
3229 case flexible_unit_scanned:
3230
3231 if (mu) {
3232 tex_aux_scan_dimension_unknown_unit_error();
3233 } else if (! inf) {
3234 if (! order && lmt_error_state.intercept) {
3235 lmt_error_state.last_intercept = 1;
3236 } else {
3237 tex_aux_scan_dimension_fi_error();
3238 }
3239 }
3240 goto ATTACH_FRACTION;
3241 case quantitity_unit_scanned:
3242
3243 cur_val = tex_aux_scan_something_internal(cur_cmd, cur_chr, mu ? muglue_val_level : dimension_val_level, 0, 0);
3244 if (mu) {
3245 cur_val = tex_aux_coerced_glue(cur_val, cur_val_level);
3246 if (cur_val_level != muglue_val_level) {
3247 tex_aux_mu_error(3);
3248 }
3249 }
3250 v = cur_val;
3251 cur_val = tex_nx_plus_y(save_cur_val, v, tex_xn_over_d(v, fraction, 0200000));
3252 goto ATTACH_SIGN;
3253 }
3254 }
3255 ATTACH_FRACTION:
3256 if (cur_val >= 040000) {
3257 lmt_scanner_state.arithmic_error = 1;
3258 } else {
3259 cur_val = cur_val * unity + fraction;
3260 }
3261 DONE:
3262 tex_get_x_token();
3263 tex_push_back(cur_tok, cur_cmd, cur_chr);
3264 ATTACH_SIGN:
3265 if (lmt_scanner_state.arithmic_error || (abs(cur_val) >= 010000000000)) {
3266 if (lmt_error_state.intercept) {
3267 lmt_error_state.last_intercept = 1;
3268 } else {
3269 tex_aux_scan_dimension_out_of_range_error();
3270 }
3271 cur_val = max_dimension;
3272 lmt_scanner_state.arithmic_error = 0;
3273 }
3274 if (negative) {
3275 cur_val = -cur_val;
3276 }
3277 if (order) {
3278 *order = cur_order;
3279 }
3280 return cur_val;
3281}
3282
3283
3284void tex_scan_dimension_validate(void)
3285{
3286 lmt_scanner_state.arithmic_error = 0;
3287 while (1) {
3288 tex_get_x_token();
3289 if (cur_cmd == spacer_cmd || cur_tok == minus_token) {
3290 continue;
3291 } else if (cur_tok != plus_token) {
3292 break;
3293 }
3294 }
3295 if (cur_cmd >= min_internal_cmd && cur_cmd <= max_internal_cmd) {
3296 tex_aux_scan_something_internal(cur_cmd, cur_chr, dimension_val_level, 0, 0);
3297 if (cur_val_level == dimension_val_level || cur_val_level == posit_val_level) {
3298 return;
3299 }
3300 } else {
3301 int has_fraction = tex_token_is_seperator(cur_tok);
3302 if (! has_fraction) {
3303 int cur_radix;
3304 tex_back_input(cur_tok);
3305 tex_scan_integer(0, &cur_radix);
3306 if (cur_radix == 10 && tex_token_is_seperator(cur_tok)) {
3307 has_fraction = 1;
3308 tex_get_token();
3309 }
3310 }
3311 if (has_fraction) {
3312 while (1) {
3313 tex_get_x_token();
3314 if (cur_tok > nine_token || cur_tok < zero_token) {
3315 break;
3316 }
3317 }
3318 if (cur_cmd != spacer_cmd) {
3319 tex_back_input(cur_tok);
3320 }
3321 }
3322 }
3323 {
3324 int num = 0;
3325 int denom = 0;
3326 scaled value;
3327 switch (tex_aux_scan_unit(&num, &denom, &value, NULL)) {
3328 case no_unit_scanned:
3329 case flexible_unit_scanned:
3330 lmt_error_state.last_intercept = 1;
3331 break;
3332 case normal_unit_scanned:
3333 case scaled_point_scanned:
3334 case relative_unit_scanned:
3335 case math_unit_scanned:
3336 break;
3337 case quantitity_unit_scanned:
3338 tex_aux_scan_something_internal(cur_cmd, cur_chr, dimension_val_level, 0, 0);
3339 return;
3340 }
3341 }
3342 tex_get_x_token();
3343 tex_push_back(cur_tok, cur_cmd, cur_chr);
3344}
3345
3346
3357
3358
3359
3360halfword tex_scan_glue(int level, int optional_equal, int options_too)
3361{
3362
3363 bool negative = false;
3364
3365 halfword q = null;
3366
3367 int mu = level == muglue_val_level;
3368
3369 do {
3370
3371 while (1) {
3372 tex_get_x_token();
3373 if (cur_cmd != spacer_cmd) {
3374 if (optional_equal && (cur_tok == equal_token)) {
3375 optional_equal = 0;
3376 } else {
3377 break;
3378 }
3379 }
3380 }
3381 if (cur_tok == minus_token) {
3382 negative = ! negative;
3383 cur_tok = plus_token;
3384 }
3385 } while (cur_tok == plus_token);
3386 if (cur_cmd >= min_internal_cmd && cur_cmd <= max_internal_cmd) {
3387 cur_val = tex_aux_scan_something_internal(cur_cmd, cur_chr, level, negative, 0);
3388 if (cur_val_level >= glue_val_level) {
3389 if (cur_val_level != level) {
3390 tex_aux_mu_error(4);
3391 }
3392 return cur_val;
3393 }
3394 if (cur_val_level == integer_val_level) {
3395 cur_val = tex_scan_dimension(mu, 0, 1, 0, NULL);
3396
3401
3402
3403 } else if (level == muglue_val_level) {
3404 tex_aux_mu_error(5);
3405 }
3406 } else {
3407 tex_back_input(cur_tok);
3408 cur_val = tex_scan_dimension(mu, 0, 0, 0, NULL);
3409 if (negative) {
3410 cur_val = -cur_val;
3411 }
3412 }
3413
3417 q = tex_new_glue_spec_node(zero_glue);
3418 glue_amount(q) = cur_val;
3419 while (1) {
3420 switch (tex_scan_character("pmlPML", 0, 1, 0)) {
3421 case 0:
3422 return q;
3423 case 'p': case 'P':
3424 if (tex_scan_mandate_keyword("plus", 1)) {
3425 halfword order;
3426 glue_stretch(q) = tex_scan_dimension(mu, 1, 0, 0, &order);
3427 glue_stretch_order(q) = order;
3428 }
3429 break;
3430 case 'm': case 'M':
3431 if (tex_scan_mandate_keyword("minus", 1)) {
3432 halfword order;
3433 glue_shrink(q) = tex_scan_dimension(mu, 1, 0, 0, &order);
3434 glue_shrink_order(q) = order;
3435 }
3436 break;
3437 case 'l': case 'L':
3438 if (options_too && tex_scan_mandate_keyword("limit", 1)) {
3439 glue_options(q) |= glue_option_limit;
3440 break;
3441 } else {
3442
3443 }
3444 default:
3445 tex_aux_show_keyword_error(options_too ? "plus|minus|limit" : "plus|minus");
3446 return q;
3447 }
3448 }
3449}
3450
3451
3464
3465halfword tex_scan_font(int optional_equal)
3466{
3467 halfword fv = null;
3468 halfword id, fs;
3469 if (optional_equal) {
3470 tex_scan_optional_equals();
3471 }
3472 id = tex_scan_font_identifier(&fv);
3473 if (fv) {
3474 fs = tex_copy_node(fv);
3475 } else {
3476
3477 fs = tex_new_node(font_spec_node, normal_code);
3478 font_spec_identifier(fs) = id;
3479 font_spec_scale(fs) = unused_scale_value;
3480 font_spec_x_scale(fs) = unused_scale_value;
3481 font_spec_y_scale(fs) = unused_scale_value;
3482 font_spec_slant(fs) = 0;
3483 font_spec_weight(fs) = 0;
3484 }
3485 while (1) {
3486 switch (tex_scan_character("asxywoASXYWO", 0, 1, 0)) {
3487 case 0:
3488 return fs;
3489 case 'a': case 'A':
3490 if (tex_scan_mandate_keyword("all", 1)) {
3491 font_spec_scale(fs) = tex_scan_scale_factor(0);
3492 font_spec_x_scale(fs) = tex_scan_scale_factor(0);
3493 font_spec_y_scale(fs) = tex_scan_scale_factor(0);
3494 font_spec_slant(fs) = tex_scan_scale_factor(0);
3495 font_spec_weight(fs) = tex_scan_scale_factor(0);
3496 }
3497 break;
3498 case 's': case 'S':
3499 switch (tex_scan_character("clCL", 0, 1, 0)) {
3500 case 'c': case 'C':
3501 if (tex_scan_mandate_keyword("scale", 2)) {
3502 font_spec_scale(fs) = tex_scan_scale_factor(0);
3503 }
3504 break;
3505 case 'l': case 'L':
3506 if (tex_scan_mandate_keyword("slant", 2)) {
3507 font_spec_slant(fs) = tex_scan_scale_factor(0);
3508 }
3509 break;
3510 default:
3511 tex_aux_show_keyword_error("scale|slant");
3512 return fs;
3513 }
3514 break;
3515 case 'x': case 'X':
3516 if (tex_scan_mandate_keyword("xscale", 1)) {
3517 font_spec_x_scale(fs) = tex_scan_scale_factor(0);
3518 }
3519 break;
3520 case 'y': case 'Y':
3521 if (tex_scan_mandate_keyword("yscale", 1)) {
3522 font_spec_y_scale(fs) = tex_scan_scale_factor(0);
3523 }
3524 break;
3525 case 'w': case 'W':
3526 if (tex_scan_mandate_keyword("weight", 1)) {
3527 font_spec_weight(fs) = tex_scan_scale_factor(0);
3528 }
3529 break;
3530 case 'o': case 'O':
3531 if (tex_scan_mandate_keyword("oblique", 1)) {
3532 font_spec_slant(fs) = tex_scan_scale_factor(0);
3533 }
3534 break;
3535 default:
3536 return fs;
3537 }
3538 }
3539}
3540
3541
3550
3551# define push_selector { \
3552 saved_selector = lmt_print_state.selector; \
3553 lmt_print_state.selector = new_string_selector_code; \
3554}
3555
3556# define pop_selector { \
3557 lmt_print_state.selector = saved_selector; \
3558}
3559
3560halfword tex_the_value_toks(int code, halfword *tail, halfword property)
3561{
3562 tex_get_x_token();
3563 cur_val = tex_aux_scan_something_internal(cur_cmd, cur_chr, token_val_level, 0, property);
3564 switch (cur_val_level) {
3565 case integer_val_level:
3566 case attribute_val_level:
3567 {
3568 int saved_selector;
3569 push_selector;
3570 tex_print_int(cur_val);
3571 pop_selector;
3572 return tex_cur_str_toks(tail);
3573 }
3574 case posit_val_level:
3575 {
3576 int saved_selector;
3577 push_selector;
3578 tex_print_posit(cur_val);
3579 pop_selector;
3580 return tex_cur_str_toks(tail);
3581 }
3582 case dimension_val_level:
3583 {
3584 int saved_selector;
3585 push_selector;
3586 tex_print_dimension(cur_val, code == the_without_unit_code ? no_unit : pt_unit);
3587 pop_selector;
3588 return tex_cur_str_toks(tail);
3589 }
3590 case glue_val_level:
3591 case muglue_val_level:
3592 {
3593 int saved_selector;
3594 push_selector;
3595 tex_print_spec(cur_val, (code != the_without_unit_code) ? (cur_val_level == glue_val_level ? pt_unit : mu_unit) : no_unit);
3596 tex_flush_node(cur_val);
3597 pop_selector;
3598 return tex_cur_str_toks(tail);
3599 }
3600 case token_val_level:
3601 {
3602
3603 halfword h = null;
3604 halfword p = null;
3605 if (cur_val) {
3606
3607 halfword r = token_link(cur_val);
3608 while (r) {
3609 p = tex_store_new_token(p, token_info(r));
3610 if (! h) {
3611 h = p;
3612 }
3613 r = token_link(r);
3614 }
3615 }
3616 if (tail) {
3617 *tail = p;
3618 }
3619 return h;
3620 }
3621 case font_val_level:
3622 {
3623 int saved_selector;
3624 push_selector;
3625 tex_print_font_identifier(cur_val);
3626 pop_selector;
3627 return tex_cur_str_toks(tail);
3628 }
3629 case mathspec_val_level:
3630 {
3631
3632 if (cur_val) {
3633 int saved_selector;
3634 push_selector;
3635 tex_print_mathspec(cur_val);
3636 pop_selector;
3637 return tex_cur_str_toks(tail);
3638 } else {
3639 return null;
3640 }
3641 }
3642 case fontspec_val_level:
3643 {
3644
3645 if (cur_val) {
3646 int saved_selector;
3647 push_selector;
3648 tex_print_font_specifier(cur_val);
3649 pop_selector;
3650 return tex_cur_str_toks(tail);
3651 } else {
3652 return null;
3653 }
3654 }
3655 case list_val_level:
3656 {
3657 if (cur_val) {
3658
3659 halfword copy = tex_copy_node(cur_val);
3660 tex_tail_append(copy);
3661 cur_val = null;
3662 }
3663 break;
3664 }
3665 }
3666 return null;
3667}
3668
3669void tex_detokenize_list(halfword head)
3670{
3671 int saved_selector;
3672 push_selector;
3673 tex_show_token_list(head, 0, 0);
3674 pop_selector;
3675}
3676
3677halfword tex_the_detokenized_toks(halfword *tail, int expand, int protect)
3678{
3679 halfword head = expand ? tex_scan_toks_expand(0, tail, 1, protect) : tex_scan_general_text(tail);
3680 if (head) {
3681 halfword first = expand ? token_link(head) : head;
3682 if (first) {
3683 int saved_selector;
3684 push_selector;
3685 tex_show_token_list(first, 0, protect);
3686 pop_selector;
3687 tex_flush_token_list(head);
3688 return tex_cur_str_toks(tail);
3689 }
3690 }
3691 return null;
3692}
3693
3694
3701
3702halfword tex_the_toks(int code, halfword *tail)
3703{
3704 switch (code) {
3705 case the_code:
3706 case the_without_unit_code:
3707 return tex_the_value_toks(code, tail, 0);
3708
3709
3710 case unexpanded_code:
3711 return tex_scan_general_text(tail);
3712 case detokenize_code:
3713 case expanded_detokenize_code:
3714 case protected_detokenize_code:
3715 case protected_expanded_detokenize_code:
3716 return tex_the_detokenized_toks(tail,
3717 code == expanded_detokenize_code || code == protected_expanded_detokenize_code,
3718 code == protected_detokenize_code || code == protected_expanded_detokenize_code
3719 );
3720 default:
3721 return null;
3722 }
3723}
3724
3725strnumber tex_the_scanned_result(void)
3726{
3727
3728 strnumber r;
3729
3730 int saved_selector;
3731 push_selector;
3732 switch (cur_val_level) {
3733 case integer_val_level:
3734 case attribute_val_level:
3735 tex_print_int(cur_val);
3736 break;
3737 case posit_val_level:
3738 tex_print_posit(cur_val);
3739 break;
3740 case dimension_val_level:
3741 tex_print_dimension(cur_val, pt_unit);
3742 break;
3743 case glue_val_level:
3744 tex_print_spec(cur_val, pt_unit);
3745 tex_flush_node(cur_val);
3746 break;
3747 case muglue_val_level:
3748 tex_print_spec(cur_val, mu_unit);
3749 tex_flush_node(cur_val);
3750 break;
3751 case token_val_level:
3752 if (cur_val) {
3753 tex_token_show(cur_val);
3754 break;
3755 } else {
3756 r = get_nullstr();
3757 goto DONE;
3758 }
3759
3770 default:
3771 r = get_nullstr();
3772 goto DONE;
3773 }
3774 r = tex_make_string();
3775 DONE:
3776 pop_selector;
3777 return r;
3778}
3779
3780
3787
3788static halfword tex_aux_scan_font_id_and_parameter(halfword *fnt, halfword *n)
3789{
3790 *n = tex_scan_integer(0, NULL);
3791 *fnt = tex_scan_font_identifier(NULL);
3792 if (*n <= 0 || *n > max_integer) {
3793 tex_handle_error(
3794 normal_error_type,
3795 "Font '%s' has at most %i fontdimen parameters",
3796 font_original(*fnt), font_parameter_count(*fnt),
3797 "The font parameter index is out of range."
3798 );
3799 return 0;
3800 } else {
3801 return 1;
3802 }
3803}
3804
3805void tex_set_font_dimension(void)
3806{
3807 halfword fnt, n;
3808 if (tex_aux_scan_font_id_and_parameter(&fnt, &n)) {
3809 tex_set_font_parameter(fnt, n, tex_scan_dimension(0, 0, 0, 1, NULL));
3810 }
3811}
3812
3813halfword tex_get_font_dimension(void)
3814{
3815 halfword fnt, n;
3816 return tex_aux_scan_font_id_and_parameter(&fnt, &n) ? tex_get_font_parameter(fnt, n) : null;
3817}
3818
3819void tex_set_scaled_font_dimension(void)
3820{
3821 halfword fnt, n;
3822 if (tex_aux_scan_font_id_and_parameter(&fnt, &n)) {
3823 tex_set_scaled_parameter(fnt, n, tex_scan_dimension(0, 0, 0, 1, NULL));
3824 }
3825}
3826
3827halfword tex_get_scaled_font_dimension(void)
3828{
3829 halfword fnt, n;
3830 return tex_aux_scan_font_id_and_parameter(&fnt, &n) ? tex_get_scaled_parameter(fnt, n) : null;
3831}
3832
3833
3834
3835halfword tex_scan_math_style_identifier(int tolerant, int styles)
3836{
3837 halfword style = tex_scan_integer(0, NULL);
3838 if (is_valid_math_style(style)) {
3839 return style;
3840 } else if (styles && are_valid_math_styles(style)) {
3841 return style;
3842 } else if (tolerant) {
3843 return -1;
3844 } else {
3845 tex_handle_error(
3846 back_error_type,
3847 "Missing math style, treated as \\displaystyle",
3848 "A style should have been here; I inserted '\\displaystyle'."
3849 );
3850 return display_style;
3851 }
3852}
3853
3854halfword tex_scan_math_parameter(void)
3855{
3856 do {
3857 tex_get_x_token();
3858 } while (cur_cmd == spacer_cmd);
3859 if (cur_cmd == math_parameter_cmd && cur_chr < math_parameter_last) {
3860 return cur_chr;
3861 } else {
3862 tex_handle_error(
3863 normal_error_type,
3864 "Invalid math parameter",
3865 "I'm going to ignore this one."
3866 );
3867 return -1;
3868 }
3869}
3870
3871halfword tex_scan_fontspec_identifier(void)
3872{
3873
3874 do {
3875 tex_get_x_token();
3876 } while (cur_cmd == spacer_cmd);
3877 if (cur_cmd == fontspec_cmd) {
3878 return cur_chr;
3879 } else {
3880 return 0;
3881 }
3882}
3883
3884halfword tex_scan_font_identifier(halfword *spec)
3885{
3886
3887 do {
3888 tex_get_x_token();
3889 } while (cur_cmd == spacer_cmd);
3890 switch (cur_cmd) {
3891 case define_font_cmd:
3892 return cur_font_par;
3893 case set_font_cmd:
3894 return cur_chr;
3895 case fontspec_cmd:
3896 {
3897 halfword fnt = tex_get_font_identifier(cur_chr);
3898 if (fnt && spec) {
3899 *spec = fnt ? cur_chr : null;
3900 }
3901 return fnt;
3902 }
3903 case define_family_cmd:
3904 {
3905 halfword siz = cur_chr;
3906 halfword fam = tex_scan_math_family_number();
3907 halfword fnt = tex_fam_fnt(fam, siz);
3908 return fnt;
3909 }
3910 case register_integer_cmd:
3911 {
3912
3913 halfword fnt = register_integer_number(cur_chr);
3914 if (tex_is_valid_font(fnt)) {
3915 return fnt;
3916 } else {
3917 break;
3918 }
3919 }
3920 case integer_cmd:
3921 {
3922
3923 halfword fnt = cur_chr;
3924 if (tex_is_valid_font(fnt)) {
3925 return fnt;
3926 } else {
3927 break;
3928 }
3929 }
3930 case internal_integer_cmd:
3931 {
3932
3933 if (internal_integer_number(cur_chr) == font_code) {
3934 halfword fnt = tex_scan_integer(0, NULL);
3935 if (tex_is_valid_font(fnt)) {
3936 return fnt;
3937 }
3938 }
3939 break;
3940 }
3941 default:
3942 {
3943
3944 unsigned fnt = null_font;
3945 tex_back_input(cur_tok);
3946 if (tex_scan_cardinal(0, &fnt, 1)) {
3947 if (tex_is_valid_font((halfword) fnt)) {
3948 return (halfword) fnt;
3949 }
3950 }
3951 break;
3952 }
3953 }
3954 tex_handle_error(
3955 back_error_type,
3956 "Missing or invalid font identifier (or equivalent) or integer (register or otherwise)",
3957 "I was looking for a control sequence whose current meaning has been defined by\n"
3958 "\\font or a valid font id number."
3959 );
3960 return null_font;
3961}
3962
3963
3972
3973halfword tex_scan_general_text(halfword *tail)
3974{
3975
3976 halfword p = get_reference_token();
3977 halfword head;
3978
3979 halfword unbalance = 0;
3980 halfword saved_scanner_status = lmt_input_state.scanner_status;
3981 halfword saved_warning_index = lmt_input_state.warning_index;
3982 halfword saved_def_ref = lmt_input_state.def_ref;
3983 lmt_input_state.scanner_status = scanner_is_absorbing;
3984 lmt_input_state.warning_index = cur_cs;
3985 lmt_input_state.def_ref = p;
3986
3987 tex_scan_left_brace();
3988 while (1) {
3989 tex_get_token();
3990 if (! cur_cs) {
3991 switch (cur_cmd) {
3992 case left_brace_cmd:
3993 if (! cur_cs) {
3994 ++unbalance;
3995 }
3996 break;
3997 case right_brace_cmd:
3998 if (unbalance) {
3999 --unbalance;
4000 break;
4001 } else {
4002 goto DONE;
4003 }
4004 }
4005 }
4006 p = tex_store_new_token(p, cur_tok);
4007 }
4008 DONE:
4009 head = token_link(lmt_input_state.def_ref);
4010 if (tail) {
4011 *tail = head ? p : null;
4012 }
4013
4014 tex_put_available_token(lmt_input_state.def_ref);
4015 lmt_input_state.scanner_status = saved_scanner_status;
4016 lmt_input_state.warning_index = saved_warning_index;
4017 lmt_input_state.def_ref = saved_def_ref;
4018 return head;
4019}
4020
4021
4058
4059static inline bool tex_parameter_escape_mode(void)
4060{
4061 return (parameter_mode_par & parameter_escape_mode) == parameter_escape_mode;
4062}
4063
4064halfword tex_scan_toks_normal(int left_brace_found, halfword *tail)
4065{
4066 halfword unbalance = 0;
4067 halfword result = get_reference_token();
4068 halfword p = result;
4069 lmt_input_state.scanner_status = scanner_is_absorbing;
4070 lmt_input_state.warning_index = cur_cs;
4071 lmt_input_state.def_ref = result;
4072 if (! left_brace_found) {
4073 tex_scan_left_brace();
4074 }
4075 while (1) {
4076 tex_get_token();
4077 switch (cur_cmd) {
4078 case left_brace_cmd:
4079 if (! cur_cs) {
4080 ++unbalance;
4081 }
4082 break;
4083 case right_brace_cmd:
4084 if (! cur_cs) {
4085 if (unbalance) {
4086 --unbalance;
4087 } else {
4088 goto DONE;
4089 }
4090 }
4091 break;
4092 case prefix_cmd:
4093 if (cur_chr == enforced_code && (! overload_mode_par || lmt_main_state.run_state != production_state)) {
4094 cur_tok = token_val(prefix_cmd, always_code);
4095 }
4096 break;
4097 }
4098 p = tex_store_new_token(p, cur_tok);
4099 }
4100 DONE:
4101 lmt_input_state.scanner_status = scanner_is_normal;
4102 if (tail) {
4103 *tail = p;
4104 }
4105 return result;
4106}
4107
4108halfword tex_scan_toks_expand(int left_brace_found, halfword *tail, int expandconstant, int keepparameters)
4109{
4110 halfword unbalance = 0;
4111 halfword result = get_reference_token();
4112 halfword p = result;
4113 lmt_input_state.scanner_status = scanner_is_absorbing;
4114 lmt_input_state.warning_index = cur_cs;
4115 lmt_input_state.def_ref = result;
4116 if (! left_brace_found) {
4117 tex_scan_left_brace();
4118 }
4119 while (1) {
4120 PICKUP:
4121 tex_get_next();
4122 switch (cur_cmd) {
4123 case call_cmd:
4124 case tolerant_call_cmd:
4125 tex_expand_current_token();
4126 goto PICKUP;
4127 case constant_call_cmd:
4128 {
4129 halfword h = token_link(cur_chr);
4130 while (h) {
4131 p = tex_store_new_token(p, token_info(h));
4132 h = token_link(h);
4133 }
4134 goto PICKUP;
4135 }
4136 case protected_call_cmd:
4137 case tolerant_protected_call_cmd:
4138 cur_tok = cs_token_flag + cur_cs;
4139 goto APPENDTOKEN;
4140 case semi_protected_call_cmd:
4141 case tolerant_semi_protected_call_cmd:
4142 if (expandconstant) {
4143 tex_expand_current_token();
4144 goto PICKUP;
4145 } else {
4146 cur_tok = cs_token_flag + cur_cs;
4147 goto APPENDTOKEN;
4148 }
4149 case the_cmd:
4150 {
4151 halfword t = null;
4152 halfword h = tex_the_toks(cur_chr, &t);
4153 if (h) {
4154 set_token_link(p, h);
4155 p = t;
4156 }
4157 goto PICKUP;
4158 }
4159 case parameter_cmd:
4160 {
4161
4162 halfword tok1, tok2;
4163 tex_x_token();
4164 tok1 = cur_tok;
4165 tex_get_next();
4166 tex_x_token();
4167 tok2 = cur_tok;
4168 if (keepparameters || ! tex_parameter_escape_mode()) {
4169
4170 } else {
4171 halfword t;
4172 halfword h = tex_expand_parameter(tok2, &t);
4173 if (h) {
4174 set_token_link(p, h);
4175 p = t;
4176 goto PICKUP;
4177 } else {
4178 tex_flush_token_list(h);
4179 }
4180 }
4181 p = tex_store_new_token(p, tok1);
4182 p = tex_store_new_token(p, tok2);
4183 goto PICKUP;
4184 }
4185 case prefix_cmd:
4186 if (cur_chr == enforced_code && (! overload_mode_par || lmt_main_state.run_state != production_state)) {
4187 cur_tok = token_val(prefix_cmd, always_code);
4188 goto APPENDTOKEN;
4189 }
4190 default:
4191 if (cur_cmd > max_command_cmd) {
4192 tex_expand_current_token();
4193 goto PICKUP;
4194 } else {
4195 goto DONEEXPANDING;
4196 }
4197 }
4198 DONEEXPANDING:
4199 tex_x_token();
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209 if (! cur_cs) {
4210 switch (cur_cmd) {
4211 case left_brace_cmd:
4212 ++unbalance;
4213 break;
4214 case right_brace_cmd:
4215 if (unbalance) {
4216 --unbalance;
4217 } else {
4218 goto FINALYDONE;
4219 }
4220 break;
4221 }
4222 }
4223 APPENDTOKEN:
4224 p = tex_store_new_token(p, cur_tok);
4225 }
4226 FINALYDONE:
4227 lmt_input_state.scanner_status = scanner_is_normal;
4228 if (tail) {
4229 *tail = p;
4230 }
4231 return result;
4232}
4233
4234static void tex_aux_too_many_parameters_error(void)
4235{
4236 tex_handle_error(
4237 normal_error_type,
4238 "You already have 15 parameters",
4239 "I'm going to ignore the # sign you just used, as well the token that followed it.\n"
4240
4241 );
4242}
4243
4244static void tex_aux_parameters_order_error(void)
4245{
4246 tex_handle_error(
4247 back_error_type,
4248 "Parameters must be numbered consecutively",
4249 "I've inserted the digit you should have used after the #."
4250 );
4251}
4252
4253static void tex_aux_missing_brace_error(void)
4254{
4255 tex_handle_error(
4256 normal_error_type,
4257 "Missing { inserted",
4258 "Where was the left brace? You said something like '\\def\\a}', which I'm going to\n"
4259 "interpret as '\\def\\a{}'."
4260 );
4261}
4262
4263static void tex_aux_illegal_parameter_in_body_error(void)
4264{
4265 tex_handle_error(
4266 back_error_type,
4267 "Illegal parameter number in definition of %S",
4268 lmt_input_state.warning_index,
4269 "You meant to type ## instead of #, right? Or maybe a } was forgotten somewhere\n"
4270 "earlier, and things are all screwed up? I'm going to assume that you meant ##."
4271 );
4272}
4273
4274
4294
4295
4296
4297static int tex_aux_valid_macro_preamble(halfword *p, int *counter, halfword *hash_brace)
4298{
4299 halfword h = *p;
4300 while (1) {
4301 tex_get_token();
4302 switch (cur_cmd) {
4303 case left_brace_cmd:
4304 case right_brace_cmd:
4305 if (cur_cs) {
4306 break;
4307 } else {
4308 goto DONE;
4309 }
4310 case parameter_cmd:
4311 tex_get_token();
4312
4322 if (cur_tok < left_brace_limit) {
4323
4324
4325 *hash_brace = cur_tok;
4326 *p = tex_store_new_token(*p, cur_tok);
4327 *p = tex_store_new_token(*p, end_match_token);
4328 set_token_preamble(h, macro_with_preamble);
4329 set_token_parameters(h, *counter);
4330 return 1;
4331 } else if (*counter == 0xF) {
4332 tex_aux_too_many_parameters_error();
4333 } else {
4334 switch (cur_tok) {
4335 case zero_token:
4336 ++*counter;
4337 cur_tok = match_token;
4338 break;
4339 case asterisk_token:
4340 cur_tok = spacer_match_token;
4341 break;
4342 case plus_token:
4343 ++*counter;
4344 cur_tok = keep_match_token;
4345 break;
4346 case minus_token:
4347 cur_tok = thrash_match_token;
4348 break;
4349 case period_token:
4350 cur_tok = par_spacer_match_token;
4351 break;
4352 case comma_token:
4353 cur_tok = keep_spacer_match_token;
4354 break;
4355 case slash_token:
4356 ++*counter;
4357 cur_tok = prune_match_token;
4358 break;
4359 case colon_token:
4360 cur_tok = continue_match_token;
4361 break;
4362 case semi_colon_token:
4363 cur_tok = quit_match_token;
4364 break;
4365 case equal_token:
4366 ++*counter;
4367 cur_tok = mandate_match_token;
4368 break;
4369 case circumflex_token_l:
4370 case circumflex_token_o:
4371 ++*counter;
4372 cur_tok = leading_match_token;
4373 break;
4374 case underscore_token_l:
4375 case underscore_token_o:
4376 ++*counter;
4377 cur_tok = mandate_keep_match_token;
4378 break;
4379 case at_token_l:
4380 case at_token_o:
4381 cur_tok = par_command_match_token;
4382 break;
4383 case L_token_l:
4384 case L_token_o:
4385 cur_tok = left_match_token;
4386 break;
4387 case R_token_l:
4388 case R_token_o:
4389 cur_tok = right_match_token;
4390 break;
4391 case G_token_l:
4392 case G_token_o:
4393 cur_tok = gobble_match_token;
4394 break;
4395 case M_token_l:
4396 case M_token_o:
4397 cur_tok = gobble_more_match_token;
4398 break;
4399 case S_token_l:
4400 case S_token_o:
4401 cur_tok = brackets_match_token;
4402 break;
4403 case P_token_l:
4404 case P_token_o:
4405 cur_tok = parentheses_match_token;
4406 break;
4407 case X_token_l:
4408 case X_token_o:
4409 cur_tok = angles_match_token;
4410 break;
4411 default:
4412 if (cur_tok >= one_token && cur_tok <= nine_token) {
4413 ++*counter;
4414 if ((cur_tok - other_token - '0') == *counter) {
4415 cur_tok += match_token - other_token ;
4416 break;
4417 }
4418 } else if (cur_tok >= A_token_l && cur_tok <= F_token_l) {
4419 ++*counter;
4420 if ((cur_tok - A_token_l + 10) == *counter) {
4421 cur_tok += match_token - letter_token;
4422 break;
4423 }
4424 }
4425 tex_aux_parameters_order_error();
4426 cur_tok = match_token;
4427 break;
4428 }
4429 }
4430 break;
4431 case end_paragraph_cmd:
4432 if (! auto_paragraph_mode(auto_paragraph_macro)) {
4433 cur_tok = par_command_match_token;
4434 }
4435 break;
4436 }
4437 *p = tex_store_new_token(*p, cur_tok);
4438 }
4439 DONE:
4440 if (h != *p) {
4441 *p = tex_store_new_token(*p, end_match_token);
4442 set_token_preamble(h, macro_with_preamble);
4443 set_token_parameters(h, *counter);
4444 }
4445 if (cur_cmd == right_brace_cmd) {
4446 ++lmt_input_state.align_state;
4447 tex_aux_missing_brace_error();
4448 return 0;
4449 } else {
4450 return 1;
4451 }
4452}
4453
4454halfword tex_scan_macro_normal(void)
4455{
4456 halfword hash_brace = 0;
4457 halfword counter = 0;
4458 halfword result = get_reference_token();
4459 halfword p = result;
4460 lmt_input_state.scanner_status = scanner_is_defining;
4461 lmt_input_state.warning_index = cur_cs;
4462 lmt_input_state.def_ref = result;
4463 if (tex_aux_valid_macro_preamble(&p, &counter, &hash_brace)) {
4464 halfword unbalance = 0;
4465 while (1) {
4466 tex_get_token();
4467 switch (cur_cmd) {
4468 case left_brace_cmd:
4469 if (! cur_cs) {
4470 ++unbalance;
4471 }
4472 break;
4473 case right_brace_cmd:
4474 if (! cur_cs) {
4475 if (unbalance) {
4476 --unbalance;
4477 } else {
4478 goto FINALYDONE;
4479 }
4480 }
4481 break;
4482 case parameter_cmd:
4483 {
4484 halfword s = cur_tok;
4485 tex_get_token();
4486 if (cur_cmd == parameter_cmd) {
4487
4488 } else {
4489 halfword n;
4490 if (cur_tok >= one_token && cur_tok <= nine_token) {
4491 n = cur_chr - '0';
4492 } else if (cur_tok >= A_token_l && cur_tok <= F_token_l) {
4493 n = cur_chr - '0' - gap_match_count;
4494 } else {
4495 n = counter + 1;
4496 }
4497 if (n <= counter) {
4498 cur_tok = token_val(parameter_reference_cmd, n);
4499 } else {
4500 halfword v = tex_parameter_escape_mode() ? valid_parameter_reference(cur_tok) : 0;
4501 if (v) {
4502 p = tex_store_new_token(p, token_val(parameter_cmd, match_visualizer));
4503 } else {
4504 tex_aux_illegal_parameter_in_body_error();
4505 cur_tok = s;
4506 }
4507 }
4508 }
4509 }
4510 break;
4511 case prefix_cmd:
4512 if (cur_chr == enforced_code && (! overload_mode_par || lmt_main_state.run_state != production_state)) {
4513 cur_tok = token_val(prefix_cmd, always_code);
4514 }
4515 break;
4516 default:
4517 break;
4518 }
4519 p = tex_store_new_token(p, cur_tok);
4520 }
4521 }
4522 FINALYDONE:
4523 lmt_input_state.scanner_status = scanner_is_normal;
4524 if (hash_brace) {
4525 p = tex_store_new_token(p, hash_brace);
4526 }
4527 return result;
4528}
4529
4530halfword tex_scan_macro_expand(void)
4531{
4532 halfword hash_brace = 0;
4533 halfword counter = 0;
4534 halfword result = get_reference_token();
4535 halfword p = result;
4536 lmt_input_state.scanner_status = scanner_is_defining;
4537 lmt_input_state.warning_index = cur_cs;
4538 lmt_input_state.def_ref = result;
4539 if (tex_aux_valid_macro_preamble(&p, &counter, &hash_brace)) {
4540 halfword unbalance = 0;
4541 while (1) {
4542 PICKUP:
4543 tex_get_next();
4544 switch (cur_cmd) {
4545 case call_cmd:
4546 case tolerant_call_cmd:
4547 tex_expand_current_token();
4548 goto PICKUP;
4549 case index_cmd:
4550 tex_inject_parameter(cur_chr);
4551 goto PICKUP;
4552 case constant_call_cmd:
4553 {
4554 halfword h = token_link(cur_chr);
4555 while (h) {
4556 p = tex_store_new_token(p, token_info(h));
4557 h = token_link(h);
4558 }
4559 goto PICKUP;
4560 }
4561 case protected_call_cmd:
4562 case semi_protected_call_cmd:
4563 case tolerant_protected_call_cmd:
4564 case tolerant_semi_protected_call_cmd:
4565 cur_tok = cs_token_flag + cur_cs;
4566 goto APPENDTOKEN;
4567 case the_cmd:
4568 {
4569 halfword t = null;
4570 halfword h = tex_the_toks(cur_chr, &t);
4571 if (h) {
4572 set_token_link(p, h);
4573 p = t;
4574 }
4575 goto PICKUP;
4576 }
4577 case relax_cmd:
4578 if (cur_chr == no_relax_code) {
4579
4580 goto PICKUP;
4581 } else {
4582 goto DONEEXPANDING;
4583 }
4584 case prefix_cmd:
4585 if (cur_chr == enforced_code && (! overload_mode_par || lmt_main_state.run_state != production_state)) {
4586 cur_tok = token_val(prefix_cmd, always_code);
4587 goto APPENDTOKEN;
4588 } else {
4589 goto DONEEXPANDING;
4590 }
4591 case parameter_cmd:
4592 {
4593
4594 halfword s = cur_tok;
4595 tex_get_x_token();
4596 if (cur_cmd == parameter_cmd) {
4597
4598 } else {
4599 halfword n;
4600 if (cur_tok >= one_token && cur_tok <= nine_token) {
4601 n = cur_chr - '0';
4602 } else if (cur_tok >= A_token_l && cur_tok <= F_token_l) {
4603 n = cur_chr - '0' - gap_match_count;
4604 } else {
4605 n = counter + 1;
4606 }
4607 if (n <= counter) {
4608 cur_tok = token_val(parameter_reference_cmd, n);
4609 } else {
4610 halfword v = tex_parameter_escape_mode() ? valid_parameter_reference(cur_tok) : 0;
4611 if (v) {
4612 halfword t = null;
4613 halfword h = tex_expand_parameter(cur_tok, &t);
4614 if (h) {
4615 set_token_link(p, h);
4616 p = t;
4617 }
4618 goto PICKUP;
4619 } else {
4620 tex_aux_illegal_parameter_in_body_error();
4621 cur_tok = s;
4622 }
4623 }
4624 }
4625 goto APPENDTOKEN;
4626 }
4627 case left_brace_cmd:
4628 if (cur_cs) {
4629 cur_tok = cs_token_flag + cur_cs;
4630 } else {
4631 cur_tok = token_val(cur_cmd, cur_chr);
4632 ++unbalance;
4633 }
4634 goto APPENDTOKEN;
4635 case right_brace_cmd:
4636 if (cur_cs) {
4637 cur_tok = cs_token_flag + cur_cs;
4638 goto APPENDTOKEN;
4639 } else {
4640 cur_tok = token_val(cur_cmd, cur_chr);
4641 if (unbalance) {
4642 --unbalance;
4643 goto APPENDTOKEN;
4644 } else {
4645 goto FINALYDONE;
4646 }
4647 }
4648 default:
4649 if (cur_cmd > max_command_cmd) {
4650 tex_expand_current_token();
4651 goto PICKUP;
4652 } else {
4653 goto DONEEXPANDING;
4654 }
4655 }
4656 DONEEXPANDING:
4657 if (cur_cs) {
4658 cur_tok = cs_token_flag + cur_cs;
4659 } else {
4660 cur_tok = token_val(cur_cmd, cur_chr);
4661 }
4662 APPENDTOKEN:
4663 p = tex_store_new_token(p, cur_tok);
4664 }
4665 }
4666 FINALYDONE:
4667 lmt_input_state.scanner_status = scanner_is_normal;
4668 if (hash_brace) {
4669 p = tex_store_new_token(p, hash_brace);
4670 }
4671 return result;
4672}
4673
4674
4681
4682typedef enum expression_states {
4683 expression_none,
4684 expression_add,
4685 expression_subtract,
4686 expression_multiply,
4687 expression_divide,
4688 expression_scale,
4689 expression_idivide,
4690 expression_imodulo,
4691} expression_states;
4692
4693
4703
4704inline static void tex_aux_normalize_glue(halfword g)
4705{
4706 if (! glue_stretch(g)) {
4707 glue_stretch_order(g) = normal_glue_order;
4708 }
4709 if (! glue_shrink(g)) {
4710 glue_shrink_order(g) = normal_glue_order;
4711 }
4712}
4713
4714
4727
4728inline static int tex_aux_add_or_sub(int x, int y, int max_answer, int operation)
4729{
4730 switch (operation) {
4731 case expression_subtract:
4732 y = -y;
4733
4734 case expression_add:
4735 if (x >= 0) {
4736 if (y <= max_answer - x) {
4737 return x + y;
4738 } else {
4739 lmt_scanner_state.arithmic_error = 1;
4740 }
4741 } else if (y >= -max_answer - x) {
4742 return x + y;
4743 } else {
4744 lmt_scanner_state.arithmic_error = 1;
4745 }
4746 break;
4747 }
4748 return 0;
4749}
4750
4751
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794inline static int tex_aux_quotient(int n, int d, int rounded)
4795{
4796 if (d == 0) {
4797 lmt_scanner_state.arithmic_error = 1;
4798 return 0;
4799 } else if (rounded) {
4800 return lround((double) n / (double) d);
4801 } else {
4802 return n / d;
4803 }
4804}
4805
4806inline static int tex_aux_modulo(int n, int d)
4807{
4808 if (d == 0) {
4809 lmt_scanner_state.arithmic_error = 1;
4810 return 0;
4811 } else {
4812 return n % d;
4813 }
4814}
4815
4816int tex_quotient(int n, int d, int round)
4817{
4818 return tex_aux_quotient(n, d, round);
4819}
4820
4821
4832
4833int tex_fract(int x, int n, int d, int max_answer)
4834{
4835
4836 bool negative = false;
4837
4838 int a = 0;
4839
4840 int f;
4841
4842 int h;
4843
4844 int r;
4845
4846 int t;
4847 if (d == 0) {
4848 goto TOO_BIG;
4849 }
4850 if (x == 0) {
4851 return 0;
4852 }
4853 if (d < 0) {
4854 d = -d;
4855 negative = true;
4856 }
4857 if (x < 0) {
4858 x = -x;
4859 negative = ! negative;
4860 }
4861 if (n < 0) {
4862 n = -n;
4863 negative = ! negative;
4864 }
4865 t = n / d;
4866 if (t > max_answer / x) {
4867 goto TOO_BIG;
4868 }
4869 a = t * x;
4870 n = n - t * d;
4871 if (n == 0) {
4872 goto FOUND;
4873 }
4874 t = x / d;
4875 if (t > (max_answer - a) / n) {
4876 goto TOO_BIG;
4877 }
4878 a = a + t * n;
4879 x = x - t * d;
4880 if (x == 0) {
4881 goto FOUND;
4882 }
4883 if (x < n) {
4884 t = x;
4885 x = n;
4886 n = t;
4887 }
4888
4899 f = 0;
4900 r = (d / 2) - d;
4901 h = -r;
4902 while (1) {
4903 if (odd(n)) {
4904 r = r + x;
4905 if (r >= 0) {
4906 r = r - d;
4907 ++f;
4908 }
4909 }
4910 n = n / 2;
4911 if (n == 0) {
4912 break;
4913 } else if (x < h) {
4914 x = x + x;
4915 } else {
4916 t = x - d;
4917 x = t + x;
4918 f = f + n;
4919 if (x < n) {
4920 if (x == 0) {
4921 break;
4922 } else {
4923 t = x;
4924 x = n;
4925 n = t;
4926 }
4927 }
4928 }
4929 }
4930 if (f > (max_answer - a)) {
4931 goto TOO_BIG;
4932 }
4933 a = a + f;
4934 FOUND:
4935 if (negative) {
4936 a = -a;
4937 }
4938 goto DONE;
4939 TOO_BIG:
4940 lmt_scanner_state.arithmic_error = 1;
4941 a = 0;
4942 DONE:
4943 return a;
4944}
4945
4946
4952
4953static void tex_aux_scan_expr(halfword level)
4954{
4955
4956 int result;
4957
4958 int state;
4959
4960 int operation;
4961
4962 int expression;
4963
4964 int term;
4965
4966 int factor = 0;
4967
4968 int numerator;
4969
4970 int error_a = lmt_scanner_state.arithmic_error;
4971 int error_b = 0;
4972
4973 halfword top = null;
4974 int braced = 0;
4975 int nonelevel = level == posit_val_level ? posit_val_level : integer_val_level;
4976
4977 cur_val_level = level;
4978 lmt_scanner_state.expression_depth++;
4979 if (lmt_scanner_state.expression_depth > 1000) {
4980 tex_fatal_error("\\*expr can only be nested 1000 deep");
4981 }
4982 RESTART:
4983 result = expression_none;
4984 state = expression_none;
4985 expression = 0;
4986 term = 0;
4987 numerator = 0;
4988 CONTINUE:
4989
4990 operation = state == expression_none ? level : nonelevel;
4991
4995 AGAIN:
4996 do {
4997 tex_get_x_token();
4998 } while (cur_cmd == spacer_cmd);
4999 if (! braced) {
5000 if (cur_cmd == left_brace_cmd) {
5001 braced = 1;
5002 goto AGAIN;
5003 } else {
5004 braced = 2;
5005 }
5006 }
5007 if (cur_tok == left_parent_token) {
5008
5009 halfword t = tex_get_node(expression_node_size);
5010 node_type(t) = expression_node;
5011 node_subtype(t) = 0;
5012
5013 node_next(t) = top;
5014 expression_type(t) = (singleword) level;
5015 expression_state(t) = (singleword) state;
5016 expression_result(t) = (singleword) result;
5017 expression_expression(t) = expression;
5018 expression_term(t) = term;
5019 expression_numerator(t) = numerator;
5020 top = t;
5021 level = operation;
5022 goto RESTART;
5023 }
5024 if (cur_cmd != spacer_cmd) {
5025 tex_back_input(cur_tok);
5026 }
5027 switch (operation) {
5028 case integer_val_level:
5029 case attribute_val_level:
5030 factor = tex_scan_integer(0, NULL);
5031 break;
5032 case posit_val_level:
5033 factor = tex_scan_posit(0);
5034 break;
5035 case dimension_val_level:
5036 factor = tex_scan_dimension(0, 0, 0, 0, NULL);
5037 break;
5038 case glue_val_level:
5039 factor = tex_scan_glue(glue_val_level, 0, 0);
5040 break;
5041 case muglue_val_level:
5042 factor = tex_scan_glue(muglue_val_level, 0, 0);
5043 break;
5044 }
5045 FOUND:
5046
5049 do {
5050 tex_get_x_token();
5051 } while (cur_cmd == spacer_cmd);
5052 switch (cur_tok) {
5053 case plus_token:
5054 operation = expression_add;
5055 break;
5056 case minus_token:
5057 operation = expression_subtract;
5058 break;
5059 case asterisk_token:
5060 operation = expression_multiply;
5061 break;
5062 case slash_token:
5063 operation = expression_divide;
5064 break;
5065 case colon_token:
5066 operation = expression_idivide;
5067 break;
5068 case semi_colon_token:
5069 operation = expression_imodulo;
5070 break;
5071
5075 default:
5076 operation = expression_none;
5077 if (! top) {
5078 if (cur_cmd == relax_cmd) {
5079
5080 } else if (cur_cmd == right_brace_cmd && braced == 1) {
5081
5082 } else {
5083 tex_back_input(cur_tok);
5084 }
5085 } else if (cur_tok != right_parent_token) {
5086 tex_handle_error(
5087 back_error_type,
5088 "Missing ) inserted for expression",
5089 "I was expecting to see '+', '-', '*', '/', ':' or ')'. Didn't."
5090 );
5091 }
5092 break;
5093 }
5094 lmt_scanner_state.arithmic_error = error_b;
5095
5096 switch (level) {
5097 case integer_val_level:
5098 case attribute_val_level:
5099 if ((factor > max_integer) || (factor < min_integer)) {
5100 lmt_scanner_state.arithmic_error = 1;
5101 factor = 0;
5102 }
5103 break;
5104 case posit_val_level:
5105 if (((unsigned) factor > max_cardinal) || ((unsigned) factor < min_cardinal)) {
5106 lmt_scanner_state.arithmic_error = 1;
5107 factor = 0;
5108 }
5109 break;
5110 case dimension_val_level:
5111 if (abs(factor) > max_dimension) {
5112 lmt_scanner_state.arithmic_error = 1;
5113 factor = 0;
5114 }
5115 break;
5116 case glue_val_level:
5117 case muglue_val_level:
5118 if ((abs(glue_amount(factor)) > max_dimension) || (abs(glue_stretch(factor)) > max_dimension) || (abs(glue_shrink(factor)) > max_dimension)) {
5119 lmt_scanner_state.arithmic_error = 1;
5120 tex_reset_glue_to_zero(factor);
5121 }
5122 break;
5123 default:
5124 if ((state > expression_subtract) && ((factor > max_integer) || (factor < min_integer))) {
5125 lmt_scanner_state.arithmic_error = 1;
5126 factor = 0;
5127 }
5128 }
5129
5130 switch (state) {
5131 case expression_none:
5132
5138 term = factor;
5139 if ((level >= glue_val_level) && (operation != expression_none)) {
5140
5141 tex_aux_normalize_glue(term);
5142 } else {
5143 term = factor;
5144 }
5145 break;
5146 case expression_multiply:
5147
5151 if (operation == expression_divide) {
5152 numerator = factor;
5153 operation = expression_scale;
5154 } else {
5155 switch (level) {
5156 case integer_val_level:
5157 case attribute_val_level:
5158 term = tex_multiply_integers(term, factor);
5159 break;
5160 case posit_val_level:
5161 term = tex_posit_mul(term, factor);
5162 break;
5163 case dimension_val_level:
5164 term = tex_nx_plus_y(term, factor, 0);
5165 break;
5166 default:
5167 glue_amount(term) = tex_nx_plus_y(glue_amount(term), factor, 0);
5168 glue_stretch(term) = tex_nx_plus_y(glue_stretch(term), factor, 0);
5169 glue_shrink(term) = tex_nx_plus_y(glue_shrink(term), factor, 0);
5170 break;
5171 }
5172 }
5173 break;
5174 case expression_divide:
5175
5176 switch (level) {
5177 case integer_val_level:
5178 case attribute_val_level:
5179 case dimension_val_level:
5180 term = tex_aux_quotient(term, factor, 1);
5181 break;
5182 case posit_val_level:
5183 if (factor == 0) {
5184 lmt_scanner_state.arithmic_error = 1;
5185 term = 0;
5186 } else {
5187 term = tex_posit_div(term, factor);
5188 }
5189 break;
5190 default:
5191 glue_amount(term) = tex_aux_quotient(glue_amount(term), factor, 1);
5192 glue_stretch(term) = tex_aux_quotient(glue_stretch(term), factor, 1);
5193 glue_shrink(term) = tex_aux_quotient(glue_shrink(term), factor, 1);
5194 break;
5195 }
5196 break;
5197 case expression_scale:
5198
5199 switch (level) {
5200 case integer_val_level:
5201 case attribute_val_level:
5202 term = tex_fract(term, numerator, factor, max_integer);
5203 break;
5204 case posit_val_level:
5205 if (numerator == 0) {
5206 lmt_scanner_state.arithmic_error = 1;
5207 term = 0;
5208 } else {
5209 term = tex_posit_div(tex_posit_mul(term, factor), numerator);
5210 }
5211 break;
5212 case dimension_val_level:
5213 term = tex_fract(term, numerator, factor, max_dimension);
5214 break;
5215 default:
5216 glue_amount(term) = tex_fract(glue_amount(term), numerator, factor, max_dimension);
5217 glue_stretch(term) = tex_fract(glue_stretch(term), numerator, factor, max_dimension);
5218 glue_shrink(term) = tex_fract(glue_shrink(term), numerator, factor, max_dimension);
5219 break;
5220 }
5221 break;
5222 case expression_idivide:
5223
5224 if (level < glue_val_level) {
5225 term = tex_aux_quotient(term, factor, 0);
5226 } else {
5227 glue_amount(term) = tex_aux_quotient(glue_amount(term), factor, 0);
5228 glue_stretch(term) = tex_aux_quotient(glue_stretch(term), factor, 0);
5229 glue_shrink(term) = tex_aux_quotient(glue_shrink(term), factor, 0);
5230 }
5231 break;
5232 case expression_imodulo:
5233
5234 if (level < glue_val_level) {
5235 term = tex_aux_modulo(term, factor);
5236 } else {
5237 glue_amount(term) = tex_aux_modulo(glue_amount(term), factor);
5238 glue_stretch(term) = tex_aux_modulo(glue_stretch(term), factor);
5239 glue_shrink(term) = tex_aux_modulo(glue_shrink(term), factor);
5240 }
5241 break;
5242 }
5243 if (operation > expression_subtract) {
5244 state = operation;
5245 } else {
5246
5250 state = expression_none;
5251 if (result == expression_none) {
5252 expression = term;
5253 } else {
5254 switch (level) {
5255 case integer_val_level:
5256 case attribute_val_level:
5257 expression = tex_aux_add_or_sub(expression, term, max_integer, result);
5258 break;
5259 case posit_val_level:
5260 switch (result) {
5261 case expression_subtract:
5262 expression = tex_posit_sub(expression, term);
5263 break;
5264 case expression_add:
5265 expression = tex_posit_add(expression, term);
5266 break;
5267 }
5268 break;
5269 case dimension_val_level:
5270 expression = tex_aux_add_or_sub(expression, term, max_dimension, result);
5271 break;
5272 default :
5273
5278 glue_amount(expression) = tex_aux_add_or_sub(glue_amount(expression), glue_amount(term), max_dimension, result);
5279 if (glue_stretch_order(expression) == glue_stretch_order(term)) {
5280 glue_stretch(expression) = tex_aux_add_or_sub(glue_stretch(expression), glue_stretch(term), max_dimension, result);
5281 } else if ((glue_stretch_order(expression) < glue_stretch_order(term)) && (glue_stretch(term) != 0)) {
5282 glue_stretch(expression) = glue_stretch(term);
5283 glue_stretch_order(expression) = glue_stretch_order(term);
5284 }
5285 if (glue_shrink_order(expression) == glue_shrink_order(term)) {
5286 glue_shrink(expression) = tex_aux_add_or_sub(glue_shrink(expression), glue_shrink(term), max_dimension, result);
5287 } else if ((glue_shrink_order(expression) < glue_shrink_order(term)) && (glue_shrink(term) != 0)) {
5288 glue_shrink(expression) = glue_shrink(term);
5289 glue_shrink_order(expression) = glue_shrink_order(term);
5290 }
5291 tex_flush_node(term);
5292 tex_aux_normalize_glue(expression);
5293 break;
5294 }
5295 }
5296 result = operation;
5297 }
5298 error_b = lmt_scanner_state.arithmic_error;
5299 if (operation != expression_none) {
5300 goto CONTINUE;
5301 } else if (top) {
5302
5303 halfword t = top;
5304 top = node_next(top);
5305 factor = expression;
5306 expression = expression_expression(t);
5307 term = expression_term(t);
5308 numerator = expression_numerator(t);
5309 state = expression_state(t);
5310 result = expression_result(t);
5311 level = expression_type(t);
5312 tex_free_node(t, expression_node_size);
5313 goto FOUND;
5314 } else if (error_b) {
5315 tex_handle_error(
5316 normal_error_type,
5317 "Arithmetic overflow",
5318 "I can't evaluate this expression, since the result is out of range."
5319 );
5320 if (level >= glue_val_level) {
5321 tex_reset_glue_to_zero(expression);
5322 } else {
5323 expression = 0;
5324 }
5325 }
5326 lmt_scanner_state.arithmic_error = error_a;
5327 lmt_scanner_state.expression_depth--;
5328 cur_val_level = level;
5329 cur_val = expression;
5330}
5331
5332
5373
5374typedef enum bit_expression_states {
5375 bit_expression_none,
5376
5377 bit_expression_bor,
5378 bit_expression_band,
5379 bit_expression_bxor,
5380
5381 bit_expression_bset,
5382 bit_expression_bunset,
5383
5384 bit_expression_bleft,
5385 bit_expression_bright,
5386
5387 bit_expression_less,
5388 bit_expression_lessequal,
5389 bit_expression_equal,
5390 bit_expression_moreequal,
5391 bit_expression_more,
5392 bit_expression_unequal,
5393
5394 bit_expression_add,
5395 bit_expression_subtract,
5396
5397 bit_expression_multiply,
5398 bit_expression_divide,
5399
5400 bit_expression_mod,
5401
5402
5403
5404 bit_expression_not,
5405
5406 bit_expression_or,
5407 bit_expression_and,
5408
5409 bit_expression_open,
5410 bit_expression_close,
5411
5412 bit_expression_number,
5413 bit_expression_float,
5414 bit_expression_dimension,
5415} bit_expression_states;
5416
5417
5418static int bit_operator_precedence[] = {
5419 0,
5420 4,
5421 6,
5422 5,
5423
5424 7,
5425 7,
5426
5427 7,
5428 7,
5429
5430 3,
5431 3,
5432 3,
5433 3,
5434 3,
5435 3,
5436
5437 8,
5438 8,
5439
5440 9,
5441 9,
5442
5443 9,
5444
5445
5446
5447 10,
5448
5449 1,
5450 2,
5451
5452 0,
5453 0,
5454
5455 0,
5456 0,
5457 0,
5458};
5459
5460static const char *bit_expression_names[] = {
5461 "none", "bor", "band", "bxor", "bset", "bunset",
5462 "<<", ">>", "<", "<=", "==", ">=", ">", "<>",
5463 "+", "-", "*", "/", "mod", "not", "or", "and",
5464 "open", "close", "number", "float", "dimension"
5465};
5466
5467
5471
5472# define factor 1
5473
5474typedef struct stack_info {
5475 halfword head;
5476 halfword tail;
5477} stack_info;
5478
5479static stack_info tex_aux_new_stack(void)
5480{
5481 return (stack_info) {
5482 .head = null,
5483 .tail = null,
5484 };
5485}
5486
5487static void tex_aux_dispose_stack(stack_info *stack)
5488{
5489
5490 halfword current = stack->head;
5491 while (current) {
5492 halfword next = node_next(current);
5493 tex_free_node(current, expression_node_size);
5494 current = next;
5495 }
5496}
5497
5498static void tex_push_stack_entry(stack_info *stack, long long value)
5499{
5500 halfword n = tex_get_node(expression_node_size);
5501 node_type(n) = expression_node;
5502 node_subtype(n) = 0;
5503 expression_entry(n) = value;
5504 if (! stack->head) {
5505 stack->head = n;
5506 } else if (stack->head == stack->tail) {
5507 node_next(stack->head) = n;
5508 node_prev(n) = stack->head;
5509 } else {
5510 node_prev(n) = stack->tail;
5511 node_next(stack->tail) = n;
5512 }
5513 stack->tail = n;
5514}
5515
5516static long long tex_pop_stack_entry(stack_info *stack)
5517{
5518 halfword t = stack->tail;
5519 if (t) {
5520 long long v = expression_entry(t);
5521 if (t == stack->head) {
5522 stack->head = null;
5523 stack->tail = null;
5524 } else {
5525 stack->tail = node_prev(t);
5526 node_next(stack->tail) = null;
5527 }
5528 tex_free_node(t, temp_node_size);
5529 return v;
5530 } else {
5531 return 0;
5532 }
5533}
5534
5535static void tex_move_stack_entry(stack_info *target, stack_info *source)
5536{
5537 halfword n = source->tail;
5538 if (n == source->head) {
5539 source->head = null;
5540 source->tail = null;
5541 } else {
5542 source->tail = node_prev(n);
5543 }
5544 if (! target->head) {
5545 target->head = n;
5546 node_prev(n) = null;
5547 } else if (target->head == target->tail) {
5548 node_next(target->head) = n;
5549 node_prev(n) = target->head;
5550 } else {
5551 node_prev(n) = target->tail;
5552 node_next(target->tail) = n;
5553 }
5554 node_next(n) = null;
5555 target->tail = n;
5556}
5557
5558static void tex_take_stack_entry(stack_info *target, stack_info *source, halfword current)
5559{
5560 while (source->head != current) {
5561 halfword next = node_next(source->head);
5562 tex_free_node(source->head, temp_node_size);
5563 source->head = next;
5564 }
5565 if (current == source->tail) {
5566 source->head = null;
5567 source->tail = null;
5568 } else {
5569 source->head = node_next(current);
5570 }
5571 if (! target->head) {
5572 target->head = current;
5573 node_prev(current) = null;
5574 } else if (target->head == target->tail) {
5575 node_next(target->head) = current;
5576 node_prev(current) = target->head;
5577 } else {
5578 node_prev(current) = target->tail;
5579 node_next(target->tail) = current;
5580 }
5581 node_next(current) = null;
5582 target->tail = current;
5583}
5584
5585static halfword tex_aux_scan_unit_applied(halfword value, halfword fraction, int has_fraction, int *has_unit)
5586{
5587 do {
5588 tex_get_x_token();
5589 } while (cur_cmd == spacer_cmd);
5590 if (cur_cmd >= min_internal_cmd && cur_cmd <= max_internal_cmd) {
5591 halfword saved_val = value;
5592 value = tex_aux_scan_something_internal(cur_cmd, cur_chr, dimension_val_level, 0, 0);
5593 value = tex_nx_plus_y(saved_val, cur_val, tex_xn_over_d(cur_val, fraction, 0200000));
5594 return value;
5595 } else if (cur_cmd == letter_cmd || cur_cmd == other_char_cmd) {
5596 halfword num = 0;
5597 halfword denom = 0;
5598 halfword saved_cs = cur_cs;
5599 halfword saved_tok = cur_tok;
5600 *has_unit = 1;
5601 switch (cur_chr) {
5602 case 'p': case 'P':
5603 tex_get_x_token();
5604 if (cur_cmd == letter_cmd || cur_cmd == other_char_cmd) {
5605 switch (cur_chr) {
5606 case 't': case 'T':
5607 goto NORMALUNIT;
5608 case 'c': case 'C':
5609 num = 12;
5610 denom = 1;
5611 goto NORMALUNIT;
5612 case 'x': case 'X':
5613 return tex_nx_plus_y(value, px_dimension_par, tex_xn_over_d(px_dimension_par, fraction, 0200000));
5614 }
5615 }
5616 break;
5617 case 'c': case 'C':
5618 tex_get_x_token();
5619 if (cur_cmd == letter_cmd || cur_cmd == other_char_cmd) {
5620 switch (cur_chr) {
5621 case 'm': case 'M':
5622 num = 7227;
5623 denom = 254;
5624 goto NORMALUNIT;
5625 case 'c': case 'C':
5626 num = 14856;
5627 denom = 1157;
5628 goto NORMALUNIT;
5629 }
5630 }
5631 break;
5632 case 's': case 'S':
5633 tex_get_x_token();
5634 if (cur_cmd == letter_cmd || cur_cmd == other_char_cmd) {
5635 switch (cur_chr) {
5636 case 'p': case 'P':
5637 return scaled_point_scanned;
5638 }
5639 }
5640 break;
5641 case 't': case 'T':
5642 tex_get_x_token();
5643 if (cur_cmd == letter_cmd || cur_cmd == other_char_cmd) {
5644 switch (cur_chr) {
5645 case 's': case 'S':
5646 num = 4588;
5647 denom = 645;
5648 goto NORMALUNIT;
5649 }
5650 }
5651 break;
5652 case 'b': case 'B':
5653 tex_get_x_token();
5654 if (cur_cmd == letter_cmd || cur_cmd == other_char_cmd) {
5655 switch (cur_chr) {
5656 case 'p': case 'P':
5657 num = 7227;
5658 denom = 7200;
5659 goto NORMALUNIT;
5660 }
5661 }
5662 break;
5663 case 'i': case 'I':
5664 tex_get_x_token();
5665 if (cur_cmd == letter_cmd || cur_cmd == other_char_cmd) {
5666 switch (cur_chr) {
5667 case 'n': case 'N':
5668 num = 7227;
5669 denom = 100;
5670 goto NORMALUNIT;
5671 }
5672 }
5673 break;
5674 case 'd': case 'D':
5675 tex_get_x_token();
5676 if (cur_cmd == letter_cmd || cur_cmd == other_char_cmd) {
5677 switch (cur_chr) {
5678 case 'd': case 'D':
5679 num = 1238;
5680 denom = 1157;
5681 goto NORMALUNIT;
5682 }
5683 }
5684 break;
5685 case 'e': case 'E':
5686 tex_get_x_token();
5687 if (cur_cmd == letter_cmd || cur_cmd == other_char_cmd) {
5688 switch (cur_chr) {
5689 case 'm': case 'M':
5690 return tex_get_scaled_em_width(cur_font_par);
5691 case 'x': case 'X':
5692 return tex_get_scaled_ex_height(cur_font_par);
5693 case 's': case 'S':
5694 num = 9176;
5695 denom = 129;
5696 goto NORMALUNIT;
5697 case 'u': case 'U':
5698 num = 9176 * eu_factor_par;
5699 denom = 129 * 10;
5700 goto NORMALUNIT;
5701 }
5702 }
5703 break;
5704 default:
5705 goto HALFUNIT;
5706 }
5707 goto NOUNIT;
5708 NORMALUNIT:
5709 if (num) {
5710 int remainder = 0;
5711 value = tex_xn_over_d_r(value, num, denom, &remainder);
5712 fraction = (num * fraction + 0200000 * remainder) / denom;
5713 value += fraction / 0200000;
5714 fraction = fraction % 0200000;
5715 }
5716 if (value >= 040000) {
5717 lmt_scanner_state.arithmic_error = 1;
5718 } else {
5719 value = value * unity + fraction;
5720 }
5721 return value;
5722 NOUNIT:
5723 tex_back_input(cur_tok);
5724 HALFUNIT:
5725 tex_back_input(saved_tok);
5726 cur_cs = saved_cs;
5727 cur_tok = saved_tok;
5728 } else {
5729 tex_back_input(cur_tok);
5730 }
5731 if (has_fraction) {
5732 *has_unit = 0;
5733 if (value >= 040000) {
5734 lmt_scanner_state.arithmic_error = 1;
5735 } else {
5736 value = value * unity + fraction;
5737 }
5738 }
5739 return value;
5740}
5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788static halfword tex_scan_bit_int(int *radix)
5789{
5790 bool negative = false;
5791 long long result = 0;
5792 do {
5793 if (cur_tok == minus_token) {
5794 negative = ! negative;
5795 cur_tok = plus_token;
5796 }
5797 } while (cur_tok == plus_token);
5798 if (cur_tok == alpha_token) {
5799 tex_get_token();
5800 if (cur_tok < cs_token_flag) {
5801 result = cur_chr;
5802 } else {
5803 strnumber txt = cs_text(cur_tok - cs_token_flag);
5804 if (tex_single_letter(txt)) {
5805 result = aux_str2uni(str_string(txt));
5806 } else if (tex_is_active_cs(txt)) {
5807 result = active_cs_value(txt);
5808 } else {
5809 result = max_character_code + 1;
5810 }
5811 }
5812 if (result > max_character_code) {
5813 tex_aux_improper_constant_error();
5814 return 0;
5815 }
5816 } else if ((cur_cmd >= min_internal_cmd && cur_cmd <= max_internal_cmd) || cur_cmd == parameter_cmd) {
5817 result = tex_aux_scan_something_internal(cur_cmd, cur_chr, integer_val_level, 0, 0);
5818 if (cur_val_level != integer_val_level) {
5819 tex_aux_missing_number_error();
5820 return 0;
5821 }
5822 } else {
5823 bool vacuous = true;
5824 bool ok_so_far = true;
5825 switch (cur_tok) {
5826 case octal_token:
5827 {
5828 if (radix) {
5829 *radix = 8;
5830 }
5831 while (1) {
5832 unsigned d = 0;
5833 tex_get_x_token();
5834 if ((cur_tok >= zero_token) && (cur_tok <= seven_token)) {
5835 d = cur_tok - zero_token;
5836 } else {
5837 goto DONE;
5838 }
5839 vacuous = false;
5840 if (ok_so_far) {
5841 result = result * 8 + d;
5842 if (result > max_integer) {
5843 result = max_integer;
5844 tex_aux_number_to_big_error();
5845 ok_so_far = false;
5846 }
5847 }
5848 }
5849
5850 }
5851 case hex_token:
5852 {
5853 if (radix) {
5854 *radix = 16;
5855 }
5856 while (1) {
5857 unsigned d = 0;
5858 tex_get_x_token();
5859 if ((cur_tok >= zero_token) && (cur_tok <= nine_token)) {
5860 d = cur_tok - zero_token;
5861 } else if ((cur_tok >= A_token_l) && (cur_tok <= F_token_l)) {
5862 d = cur_tok - A_token_l + 10;
5863 } else if ((cur_tok >= A_token_o) && (cur_tok <= F_token_o)) {
5864 d = cur_tok - A_token_o + 10;
5865 } else {
5866 goto DONE;
5867 }
5868 vacuous = false;
5869 if (ok_so_far) {
5870 result = result * 16 + d;
5871 if (result > max_integer) {
5872 result = max_integer;
5873 tex_aux_number_to_big_error();
5874 ok_so_far = false;
5875 }
5876 }
5877 }
5878
5879 }
5880 default:
5881 {
5882 if (radix) {
5883 *radix = 10;
5884 }
5885 while (1) {
5886 unsigned d = 0;
5887 if ((cur_tok >= zero_token) && (cur_tok <= nine_token)) {
5888 d = cur_tok - zero_token;
5889 } else {
5890 goto DONE;
5891 }
5892 vacuous = false;
5893 if (ok_so_far) {
5894 result = result * 10 + d;
5895 if (result > max_integer) {
5896 result = max_integer;
5897 tex_aux_number_to_big_error();
5898 ok_so_far = false;
5899 }
5900 }
5901 tex_get_x_token();
5902 }
5903
5904 }
5905 }
5906 DONE:
5907 if (vacuous) {
5908 tex_aux_missing_number_error();
5909 } else {
5910 tex_push_back(cur_tok, cur_cmd, cur_chr);
5911 }
5912 }
5913 cur_val = (halfword) (negative ? - result : result);
5914 return cur_val;
5915}
5916
5917static halfword tex_scan_bit_dimension(int *has_fraction, int *has_unit)
5918{
5919 bool negative = false;
5920 int fraction = 0;
5921 *has_fraction = 0;
5922 *has_unit = 1;
5923 lmt_scanner_state.arithmic_error = 0;
5924 do {
5925 if (cur_tok == minus_token) {
5926 negative = ! negative;
5927 cur_tok = plus_token;
5928 }
5929 } while (cur_tok == plus_token);
5930 if (cur_cmd >= min_internal_cmd && cur_cmd <= max_internal_cmd) {
5931 cur_val = tex_aux_scan_something_internal(cur_cmd, cur_chr, integer_val_level, 0, 0);
5932 if (cur_val_level == dimension_val_level) {
5933 goto ATTACH_SIGN;
5934 }
5935 } else {
5936 *has_fraction = tex_token_is_seperator(cur_tok);
5937 if (*has_fraction) {
5938
5939 cur_val = 0;
5940 } else {
5941 int cur_radix = 10;
5942 cur_val = tex_scan_bit_int(&cur_radix);
5943 if (cur_radix == 10 && tex_token_is_seperator(cur_tok)) {
5944 *has_fraction = 1;
5945 tex_get_token();
5946 }
5947 }
5948 if (*has_fraction) {
5949 unsigned k = 0;
5950 unsigned char digits[18];
5951 while (1) {
5952 tex_get_x_token();
5953 if (cur_tok > nine_token || cur_tok < zero_token) {
5954 break;
5955 } else if (k < 17) {
5956 digits[k] = (unsigned char) (cur_tok - zero_token);
5957 ++k;
5958 }
5959 }
5960 fraction = tex_round_decimals_digits(digits, k);
5961 if (cur_cmd != spacer_cmd) {
5962
5963 tex_back_input(cur_tok);
5964 }
5965 }
5966 }
5967 if (cur_val < 0) {
5968 negative = ! negative;
5969 cur_val = - cur_val;
5970 }
5971 cur_val = tex_aux_scan_unit_applied(cur_val, fraction, *has_fraction, has_unit);
5972 ATTACH_SIGN:
5973 if (lmt_scanner_state.arithmic_error || (abs(cur_val) >= 010000000000)) {
5974 tex_aux_scan_dimension_out_of_range_error();
5975 cur_val = max_dimension;
5976 lmt_scanner_state.arithmic_error = 0;
5977 }
5978 if (negative) {
5979 cur_val = -cur_val;
5980 }
5981 return cur_val;
5982}
5983
5984static void tex_aux_trace_expression(stack_info stack, halfword level, halfword n, int what)
5985{
5986 tex_begin_diagnostic();
5987 if (n > 0) {
5988 tex_print_format(level == dimension_val_level ? "[dimexpression rpn %i %s:" : "[numexpression rpn %i %s:", n, what ? "r" :"s");
5989 if (! stack.head) {
5990 tex_print_char(' ');
5991 }
5992 } else {
5993 tex_print_str(level == dimension_val_level ? "[dimexpression rpn:" : "[numexpression rpn:");
5994 }
5995 for (halfword current = stack.head; current; current = node_next(current)) {
5996 tex_print_char(' ');
5997 switch (node_subtype(current)) {
5998 case bit_expression_number:
5999 tex_print_int(scaledround((double) expression_entry(current) / factor));
6000 break;
6001 case bit_expression_float:
6002 tex_print_dimension(scaledround((double) expression_entry(current) / factor), no_unit);
6003 break;
6004 case bit_expression_dimension:
6005 tex_print_char('(');
6006 tex_print_dimension(scaledround((double) expression_entry(current) / factor), no_unit);
6007 tex_print_char(')');
6008 break;
6009 default:
6010 tex_print_str(bit_expression_names[expression_entry(current)]);
6011 break;
6012 }
6013 }
6014 tex_print_char(']');
6015 tex_end_diagnostic();
6016}
6017
6018
6019
6020static void tex_aux_scan_expression(int level)
6021{
6022 stack_info operators = tex_aux_new_stack();
6023 stack_info reverse = tex_aux_new_stack();
6024 stack_info stack = tex_aux_new_stack();
6025 halfword operation = bit_expression_none;
6026 bool alreadygotten = false;
6027 int braced = 0;
6028 int trace = tracing_expressions_par;
6029 while (1) {
6030 if (alreadygotten) {
6031 alreadygotten = false;
6032 } else {
6033 tex_get_x_token();
6034 }
6035 operation = bit_expression_none;
6036 switch (cur_cmd) {
6037 case relax_cmd:
6038 goto COLLECTED;
6039 case left_brace_cmd:
6040 if (! braced) {
6041 braced = 1;
6042 continue;
6043 } else {
6044 goto NUMBER;
6045
6046 }
6047 case right_brace_cmd:
6048 if (braced) {
6049 goto COLLECTED;
6050 } else {
6051 goto NUMBER;
6052
6053 }
6054 case spacer_cmd:
6055 continue;
6056 case superscript_cmd:
6057 switch (cur_chr) {
6058 case '^':
6059 operation = bit_expression_bxor;
6060 goto OKAY;
6061 }
6062 goto UNEXPECTED;
6063 case alignment_tab_cmd:
6064 switch (cur_chr) {
6065 case '&':
6066 tex_get_x_token();
6067 switch (cur_cmd) {
6068 case letter_cmd:
6069 case other_char_cmd:
6070 case alignment_tab_cmd:
6071 switch (cur_chr) {
6072 case '&':
6073 operation = bit_expression_and;
6074 goto OKAY;
6075 default:
6076 operation = bit_expression_band;
6077 alreadygotten = true;
6078 goto OKAY;
6079 }
6080 }
6081 }
6082 goto UNEXPECTED;
6083 case letter_cmd:
6084 case other_char_cmd:
6085 switch (cur_chr) {
6086 case '(':
6087 tex_push_stack_entry(&operators, bit_expression_open);
6088 continue;
6089 case ')':
6090 while (operators.tail && expression_entry(operators.tail) != bit_expression_open) {
6091 tex_move_stack_entry(&reverse, &operators);
6092 }
6093 tex_pop_stack_entry(&operators);
6094 continue;
6095 case '+':
6096 operation = bit_expression_add;
6097 break;
6098 case '-':
6099 operation = bit_expression_subtract;
6100 break;
6101 case '*':
6102 operation = bit_expression_multiply;
6103 break;
6104 case '/':
6105 case ':':
6106 operation = bit_expression_divide;
6107 break;
6108 case '%':
6109 case ';':
6110 operation = bit_expression_mod;
6111 break;
6112 case '&':
6113 tex_get_x_token();
6114 switch (cur_cmd) {
6115 case letter_cmd:
6116 case other_char_cmd:
6117 case alignment_tab_cmd:
6118 switch (cur_chr) {
6119 case '&':
6120 operation = bit_expression_and;
6121 goto OKAY;
6122 }
6123 }
6124 operation = bit_expression_band;
6125 alreadygotten = true;
6126 break;
6127 case '^':
6128 operation = bit_expression_bxor;
6129 break;
6130 case 'v':
6131 operation = bit_expression_bor;
6132 break;
6133 case '|':
6134 tex_get_x_token();
6135 switch (cur_cmd) {
6136 case letter_cmd:
6137 case other_char_cmd:
6138 switch (cur_chr) {
6139 case '|':
6140 operation = bit_expression_or;
6141 goto OKAY;
6142 }
6143 }
6144 operation = bit_expression_bor;
6145 alreadygotten = true;
6146 break;
6147 case '<':
6148 tex_get_x_token();
6149 switch (cur_cmd) {
6150 case letter_cmd:
6151 case other_char_cmd:
6152 switch (cur_chr) {
6153 case '<':
6154 operation = bit_expression_bleft;
6155 goto OKAY;
6156 case '=':
6157 operation = bit_expression_lessequal;
6158 goto OKAY;
6159 case '>':
6160 operation = bit_expression_unequal;
6161 goto OKAY;
6162 }
6163 }
6164 operation = bit_expression_less;
6165 alreadygotten = true;
6166 break;
6167 case '>':
6168 tex_get_x_token();
6169 switch (cur_cmd) {
6170 case letter_cmd:
6171 case other_char_cmd:
6172 switch (cur_chr) {
6173 case '>':
6174 operation = bit_expression_bright;
6175 goto OKAY;
6176 case '=':
6177 operation = bit_expression_moreequal;
6178 goto OKAY;
6179 }
6180 }
6181 operation = bit_expression_more;
6182 alreadygotten = true;
6183 break;
6184 case '=':
6185 tex_get_x_token();
6186 switch (cur_cmd) {
6187 case letter_cmd:
6188 case other_char_cmd:
6189 switch (cur_chr) {
6190 case '=':
6191 break;
6192 default:
6193 alreadygotten = true;
6194 break;
6195 }
6196 }
6197 operation = bit_expression_equal;
6198 break;
6199 case '~': case '!':
6200 tex_get_x_token();
6201 switch (cur_cmd) {
6202 case letter_cmd:
6203 case other_char_cmd:
6204 switch (cur_chr) {
6205 case '=':
6206 operation = bit_expression_unequal;
6207 goto OKAY;
6208 }
6209 }
6210 operation = bit_expression_not;
6211 alreadygotten = true;
6212 break;
6213 case 'm': case 'M':
6214 tex_get_x_token();
6215 switch (cur_cmd) {
6216 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'o': case 'O':
6217 tex_get_x_token();
6218 switch (cur_cmd) {
6219 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'd': case 'D':
6220 operation = bit_expression_mod;
6221 goto OKAY;
6222 }
6223 }
6224 }
6225 }
6226 goto UNEXPECTED;
6227 case 'n': case 'N':
6228 tex_get_x_token();
6229 switch (cur_cmd) {
6230 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'o': case 'O':
6231 tex_get_x_token();
6232 switch (cur_cmd) {
6233 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'o': case 'T':
6234 operation = bit_expression_not;
6235 goto OKAY;
6236 }
6237 }
6238 }
6239 }
6240 goto UNEXPECTED;
6241 case 'a': case 'A':
6242 tex_get_x_token();
6243 switch (cur_cmd) {
6244 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'n': case 'N':
6245 tex_get_x_token();
6246 switch (cur_cmd) {
6247 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'd': case 'D':
6248 operation = bit_expression_and;
6249 goto OKAY;
6250 }
6251 }
6252 }
6253 }
6254 goto UNEXPECTED;
6255 case 'b': case 'B':
6256 tex_get_x_token();
6257 switch (cur_cmd) {
6258 case letter_cmd: case other_char_cmd:
6259 switch (cur_chr) {
6260 case 'a': case 'A':
6261 tex_get_x_token();
6262 switch (cur_cmd) {
6263 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'n': case 'N':
6264 tex_get_x_token();
6265 switch (cur_cmd) {
6266 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'd': case 'D':
6267 operation = bit_expression_band;
6268 goto OKAY;
6269 }
6270 }
6271 }
6272 }
6273 break;
6274 case 'o': case 'O':
6275 tex_get_x_token();
6276 switch (cur_cmd) {
6277 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'r': case 'R':
6278 operation = bit_expression_bor;
6279 goto OKAY;
6280 }
6281 }
6282 break;
6283 case 'x': case 'X':
6284 tex_get_x_token();
6285 switch (cur_cmd) {
6286 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'o': case 'O':
6287 tex_get_x_token();
6288 switch (cur_cmd) {
6289 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'r': case 'R':
6290 operation = bit_expression_bxor;
6291 goto OKAY;
6292 }
6293 }
6294 }
6295 }
6296 break;
6297 case 's': case 'S':
6298 tex_get_x_token();
6299 switch (cur_cmd) {
6300 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'e': case 'S':
6301 tex_get_x_token();
6302 switch (cur_cmd) {
6303 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 't': case 'T':
6304 operation = bit_expression_bset;
6305 goto OKAY;
6306 }
6307 }
6308 }
6309 }
6310 break;
6311 case 'r': case 'R':
6312 tex_get_x_token();
6313 switch (cur_cmd) {
6314 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'e': case 'E':
6315 tex_get_x_token();
6316 switch (cur_cmd) {
6317 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 's': case 'S':
6318 tex_get_x_token();
6319 switch (cur_cmd) {
6320 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'e': case 'S':
6321 tex_get_x_token();
6322 switch (cur_cmd) {
6323 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 't': case 'T':
6324 operation = bit_expression_bset;
6325 goto OKAY;
6326 }
6327 }
6328 }
6329 }
6330 }
6331 }
6332 }
6333 }
6334 break;
6335 }
6336 }
6337 goto UNEXPECTED;
6338 case 'o': case 'O':
6339 tex_get_x_token();
6340 switch (cur_cmd) {
6341 case letter_cmd: case other_char_cmd: switch (cur_chr) { case 'r': case 'R':
6342 operation = bit_expression_or;
6343 goto OKAY;
6344 }
6345 }
6346 goto UNEXPECTED;
6347 default:
6348 goto NUMBER;
6349 }
6350 OKAY:
6351 while (operators.tail && bit_operator_precedence[expression_entry(operators.tail)] >= bit_operator_precedence[operation]) {
6352
6353 tex_move_stack_entry(&reverse, &operators);
6354 }
6355 tex_push_stack_entry(&operators, operation);
6356 break;
6357 default:
6358 NUMBER:
6359
6360 {
6361 int has_fraction = 0;
6362 int has_unit = 1;
6363 operation = level == dimension_val_level ? tex_scan_bit_dimension(&has_fraction, &has_unit) : tex_scan_bit_int(NULL);
6364 tex_push_stack_entry(&reverse, operation * factor);
6365 if (level == dimension_val_level && has_unit) {
6366 node_subtype(reverse.tail) = bit_expression_dimension;
6367 } else if (has_fraction) {
6368 node_subtype(reverse.tail) = bit_expression_float;
6369 } else {
6370 node_subtype(reverse.tail) = bit_expression_number;
6371 }
6372 continue;
6373 }
6374 }
6375 }
6376 COLLECTED:
6377 while (operators.tail) {
6378 tex_move_stack_entry(&reverse, &operators);
6379 }
6380
6381
6406 if (trace == 1) {
6407 tex_aux_trace_expression(reverse, level, 0, 0);
6408 }
6409 {
6410 halfword current = reverse.head;
6411 int step = 0;
6412 while (current) {
6413 halfword next = node_next(current);
6414 halfword subtype = node_subtype(current);
6415 if (trace > 1) {
6416 step = step + 1;
6417 tex_aux_trace_expression(reverse, level, step, 0);
6418 tex_aux_trace_expression(stack, level, step, 1);
6419 }
6420 switch (subtype) {
6421 case bit_expression_number:
6422 case bit_expression_float:
6423 case bit_expression_dimension:
6424 tex_take_stack_entry(&stack, &reverse, current);
6425 break;
6426 default:
6427 {
6428 halfword token = (halfword) expression_entry(current);
6429 long long v = 0;
6430 if (token == bit_expression_not) {
6431 v =~ stack.tail ? expression_entry(stack.tail) : 0;
6432 } else {
6433 quarterword sa, sb;
6434 long long va, vb;
6435 sb = node_subtype(stack.tail);
6436 vb = tex_pop_stack_entry(&stack);
6437 if (stack.tail) {
6438 sa = node_subtype(stack.tail);
6439 va = expression_entry(stack.tail);
6440 } else {
6441 sa = bit_expression_number;
6442 va = 0;
6443 }
6444 switch (token) {
6445 case bit_expression_bor:
6446 v = va | vb;
6447 break;
6448 case bit_expression_band:
6449 v = va & vb;
6450 break;
6451 case bit_expression_bxor:
6452 v = va ^ vb;
6453 break;
6454 case bit_expression_bset:
6455 v = va | ((long long) 1 << (vb - 1));
6456 break;
6457 case bit_expression_bunset:
6458 v = va & ~ ((long long) 1 << (vb - 1));
6459 break;
6460 case bit_expression_bleft:
6461 v = va << vb;
6462 break;
6463 case bit_expression_bright:
6464 v = va >> vb;
6465 break;
6466 case bit_expression_less:
6467 v = va < vb;
6468 break;
6469 case bit_expression_lessequal:
6470 v = va <= vb;
6471 break;
6472 case bit_expression_equal:
6473 v = va == vb;
6474 break;
6475 case bit_expression_moreequal:
6476 v = va >= vb;
6477 break;
6478 case bit_expression_more:
6479 v = va > vb;
6480 break;
6481 case bit_expression_unequal:
6482 v = va != vb;
6483 break;
6484 case bit_expression_add:
6485 v = va + vb;
6486 break;
6487 case bit_expression_subtract:
6488 v = va - vb;
6489 break;
6490 case bit_expression_multiply:
6491 {
6492 double d = (double) va * (double) vb;
6493 if (sa == bit_expression_float) {
6494 d = d / (65536 * factor);
6495 } else if (sb == bit_expression_float) {
6496 d = d / (65536 * factor);
6497 } else {
6498 d = d / factor;
6499 }
6500 if (sa == bit_expression_dimension || sb == bit_expression_dimension) {
6501 node_subtype(stack.tail) = bit_expression_dimension;
6502 }
6503 v = longlonground(d);
6504 }
6505 break;
6506 case bit_expression_divide:
6507 if (vb) {
6508 double d = (double) va / (double) vb;
6509 if (sa == bit_expression_float) {
6510
6511 d = d * (65536 * factor);
6512 } else if (sb == bit_expression_float) {
6513
6514 d = d * (65536 * factor);
6515 } else {
6516 d = d * factor;
6517 }
6518 if (sa == bit_expression_dimension || sb == bit_expression_dimension) {
6519 node_subtype(stack.tail) = bit_expression_dimension;
6520 }
6521 v = longlonground(d);
6522 } else {
6523 goto ZERO;
6524 }
6525 break;
6526 case bit_expression_mod:
6527 v = va % vb;
6528 break;
6529 case bit_expression_or:
6530 v = (va || vb) ? 1 : 0;
6531 break;
6532 case bit_expression_and:
6533 v = (va && vb) ? 1 : 0;
6534 break;
6535 default:
6536 v = 0;
6537 break;
6538 }
6539 }
6540 if (v < min_integer) {
6541 v = min_integer;
6542 } else if (v > max_integer) {
6543 v = max_integer;
6544 }
6545 expression_entry(stack.tail) = v;
6546 break;
6547 }
6548 }
6549 current = next;
6550 }
6551 }
6552 goto DONE;
6553 ZERO:
6554 tex_handle_error(
6555 back_error_type,
6556 "I can't divide by zero",
6557 "I was expecting to see a nonzero number. Didn't."
6558 );
6559 goto DONE;
6560 UNEXPECTED:
6561 tex_handle_error(
6562 back_error_type,
6563 "Premature end of bit expression",
6564 "I was expecting to see an integer or bitwise operator. Didn't."
6565 );
6566 DONE:
6567 cur_val = scaledround(((double) expression_entry(stack.tail)) / factor);
6568 cur_val_level = level;
6569 tex_aux_dispose_stack(&stack);
6570 tex_aux_dispose_stack(&reverse);
6571 tex_aux_dispose_stack(&operators);
6572}
6573
6574int tex_scanned_expression(int level)
6575{
6576 tex_aux_scan_expression(level);
6577 return cur_val;
6578}
6579
6580
6584
6585halfword tex_scan_scale(int optional_equal)
6586{
6587 bool negative = false;
6588 lmt_scanner_state.arithmic_error = 0;
6589 do {
6590 while (1) {
6591 tex_get_x_token();
6592 if (cur_cmd != spacer_cmd) {
6593 if (optional_equal && (cur_tok == equal_token)) {
6594 optional_equal = 0;
6595 } else {
6596 break;
6597 }
6598 }
6599 }
6600 if (cur_tok == minus_token) {
6601 negative = ! negative;
6602 cur_tok = plus_token;
6603 }
6604 } while (cur_tok == plus_token);
6605 if (cur_cmd >= min_internal_cmd && cur_cmd <= max_internal_cmd) {
6606 cur_val = tex_aux_scan_something_internal(cur_cmd, cur_chr, integer_val_level, 0, 0);
6607 } else {
6608 int has_fraction = tex_token_is_seperator(cur_tok);
6609 if (has_fraction) {
6610 cur_val = 0;
6611 } else {
6612 int cur_radix;
6613 tex_back_input(cur_tok);
6614 cur_val = tex_scan_integer(0, &cur_radix);
6615 tex_get_token();
6616 if (cur_radix == 10 && tex_token_is_seperator(cur_tok)) {
6617 has_fraction = 1;
6618 }
6619 }
6620 cur_val = cur_val * 1000;
6621 if (has_fraction) {
6622 unsigned k = 4;
6623 while (1) {
6624 tex_get_x_token();
6625 if (cur_tok < zero_token || cur_tok > nine_token) {
6626 break;
6627 } else if (k == 1) {
6628
6629 if (cur_tok >= five_token && cur_tok <= nine_token) {
6630 cur_val += 1;
6631 }
6632 --k;
6633 } else if (k) {
6634 cur_val = cur_val + (k == 4 ? 100 : (k == 3 ? 10 : 1)) * (cur_tok - zero_token);
6635 --k;
6636 }
6637 }
6638 }
6639 tex_push_back(cur_tok, cur_cmd, cur_chr);
6640 }
6641 if (negative) {
6642 cur_val = -cur_val;
6643 }
6644 if (lmt_scanner_state.arithmic_error || (abs(cur_val) >= 0x40000000)) {
6645
6646 cur_val = max_dimension;
6647 lmt_scanner_state.arithmic_error = 0;
6648 }
6649 return cur_val;
6650}
6651
6652
6653
6654# define max_posit_size 60
6655
6656halfword tex_scan_posit(int optional_equal)
6657{
6658 int hexadecimal = 1;
6659 int exponent = 1;
6660 bool negative = false;
6661 int b = 0;
6662 char buffer[max_posit_size+4] = { 0 };
6663 do {
6664 while (1) {
6665 tex_get_x_token();
6666 if (cur_cmd != spacer_cmd) {
6667 if (optional_equal && (cur_tok == equal_token)) {
6668 optional_equal = 0;
6669 } else {
6670 break;
6671 }
6672 }
6673 }
6674 if (cur_tok == minus_token) {
6675 negative = ! negative;
6676 cur_tok = plus_token;
6677 }
6678 } while (cur_tok == plus_token);
6679 if (cur_cmd >= min_internal_cmd && cur_cmd <= max_internal_cmd) {
6680 cur_val = tex_aux_scan_something_internal(cur_cmd, cur_chr, posit_val_level, 0, 0);
6681 } else {
6682 if (negative) {
6683 buffer[b++] = '-';
6684 }
6685
6686 if (hexadecimal && (cur_tok == zero_token)) {
6687 buffer[b++] = '0';
6688 tex_get_x_token();
6689 if (tex_token_is_hexadecimal(cur_tok)) {
6690 buffer[b++] = 'x';
6691 goto SCANHEXADECIMAL;
6692 } else {
6693 goto PICKUPDECIMAL;
6694 }
6695 } else {
6696 goto SCANDECIMAL;
6697 }
6698 SCANDECIMAL:
6699 if (tex_token_is_seperator(cur_tok)) {
6700 buffer[b++] = '.';
6701 while (1) {
6702 tex_get_x_token();
6703 if (tex_token_is_digit(cur_tok)) {
6704 buffer[b++] = (unsigned char) cur_chr;
6705 } else if (exponent) {
6706 goto DECIMALEXPONENT;
6707 } else {
6708 tex_back_input(cur_tok);
6709 goto DONE;
6710 }
6711 if (b >= 60) {
6712 goto TOOBIG;
6713 }
6714 }
6715 } else {
6716 goto PICKUPDECIMAL;
6717 }
6718 while (1) {
6719 tex_get_x_token();
6720 PICKUPDECIMAL:
6721 if (tex_token_is_digit(cur_tok)) {
6722 buffer[b++] = (unsigned char) cur_chr;
6723 } else if (tex_token_is_seperator(cur_tok)) {
6724 buffer[b++] = '.';
6725 while (1) {
6726 tex_get_x_token();
6727 if (tex_token_is_digit(cur_tok)) {
6728 buffer[b++] = (unsigned char) cur_chr;
6729 } else {
6730 tex_back_input(cur_tok);
6731 break;
6732 }
6733 }
6734 } else if (exponent) {
6735 goto DECIMALEXPONENT;
6736 } else {
6737 tex_back_input(cur_tok);
6738 goto DONE;
6739 }
6740 if (b >= max_posit_size) {
6741 goto TOOBIG;
6742 }
6743 }
6744 DECIMALEXPONENT:
6745 if (tex_token_is_exponent(cur_tok)) {
6746 buffer[b++] = (unsigned char) cur_chr;
6747 tex_get_x_token();
6748 if (tex_token_is_sign(cur_tok)) {
6749 buffer[b++] = (unsigned char) cur_chr;
6750 } else if (tex_token_is_digit(cur_tok)) {
6751 buffer[b++] = (unsigned char) cur_chr;
6752 }
6753 while (1) {
6754 tex_get_x_token();
6755 if (tex_token_is_digit(cur_tok)) {
6756 buffer[b++] = (unsigned char) cur_chr;
6757 } else {
6758 break;
6759 }
6760 if (b >= max_posit_size) {
6761 goto TOOBIG;
6762 }
6763 }
6764 }
6765 tex_back_input(cur_tok);
6766 goto DONE;
6767 SCANHEXADECIMAL:
6768 tex_get_x_token();
6769 if (tex_token_is_seperator(cur_tok)) {
6770 buffer[b++] = '.';
6771 while (1) {
6772 tex_get_x_token();
6773 if (tex_token_is_xdigit(cur_tok)) {
6774 buffer[b++] = (unsigned char) cur_chr;
6775 } else if (exponent) {
6776 goto HEXADECIMALEXPONENT;
6777 } else {
6778 tex_back_input(cur_tok);
6779 goto DONE;
6780 }
6781 if (b >= max_posit_size) {
6782 goto TOOBIG;
6783 }
6784 }
6785 } else {
6786
6787 tex_back_input(cur_tok);
6788 while (1) {
6789 tex_get_x_token();
6790 if (tex_token_is_xdigit(cur_tok)) {
6791 buffer[b++] = (unsigned char) cur_chr;
6792 } else if (tex_token_is_seperator(cur_tok)) {
6793 buffer[b++] = '.';
6794 while (1) {
6795 tex_get_x_token();
6796 if (tex_token_is_xdigit(cur_tok)) {
6797 buffer[b++] = (unsigned char) cur_chr;
6798 } else {
6799 tex_back_input(cur_tok);
6800 break;
6801 }
6802 }
6803 } else if (exponent) {
6804 goto HEXADECIMALEXPONENT;
6805 } else {
6806 tex_back_input(cur_tok);
6807 goto DONE;
6808 }
6809 if (b >= max_posit_size) {
6810 goto TOOBIG;
6811 }
6812 }
6813 }
6814 HEXADECIMALEXPONENT:
6815 if (tex_token_is_xexponent(cur_tok)) {
6816 buffer[b++] = (unsigned char) cur_chr;
6817 tex_get_x_token();
6818 if (tex_token_is_sign(cur_tok)) {
6819 buffer[b++] = (unsigned char) cur_chr;
6820 } else if (tex_token_is_xdigit(cur_tok)) {
6821 buffer[b++] = (unsigned char) cur_chr;
6822 }
6823 while (1) {
6824 tex_get_x_token();
6825 if (tex_token_is_xdigit(cur_tok)) {
6826 buffer[b++] = (unsigned char) cur_chr;
6827 } else {
6828 break;
6829 }
6830 if (b >= max_posit_size) {
6831 goto TOOBIG;
6832 }
6833 }
6834 }
6835 tex_back_input(cur_tok);
6836 DONE:
6837 if (b) {
6838 double d = strtod(buffer, NULL);
6839 cur_val = tex_double_to_posit(d).v;
6840 return cur_val;
6841 } else {
6842 tex_aux_missing_number_error();
6843 }
6844 TOOBIG:
6845 cur_val = tex_integer_to_posit(0).v;
6846 }
6847 return cur_val;
6848}
6849
6850int tex_scan_tex_value(halfword level, halfword *value)
6851{
6852 tex_aux_scan_expr(level);
6853 *value = cur_val;
6854 return 1;
6855}
6856
6857quarterword tex_scan_direction(int optional_equal)
6858{
6859 int i = tex_scan_integer(optional_equal, NULL);
6860 return (quarterword) checked_direction_value(i);
6861}
6862
6863halfword tex_scan_geometry(int optional_equal)
6864{
6865 int i = tex_scan_integer(optional_equal, NULL);
6866 return checked_geometry_value(i);
6867}
6868
6869halfword tex_scan_orientation(int optional_equal)
6870{
6871 halfword i = tex_scan_integer(optional_equal, NULL);
6872 return checked_orientation_value(i);
6873}
6874
6875halfword tex_scan_anchor(int optional_equal)
6876{
6877 halfword a = tex_scan_integer(optional_equal, NULL);
6878 halfword l = (a >> 16) & 0xFFFF;
6879 halfword r = a & 0xFFFF;
6880 return (checked_anchor_value(l) << 16) + checked_anchor_value(r);
6881}
6882
6883halfword tex_scan_anchors(int optional_equal)
6884{
6885 halfword l = tex_scan_integer(optional_equal, NULL) & 0xFFFF;
6886 halfword r = tex_scan_integer(0, NULL) & 0xFFFF;
6887 return (checked_anchor_value(l) << 16) + checked_anchor_value(r);
6888}
6889
6890halfword tex_scan_attribute(halfword attrlist)
6891{
6892 halfword i = tex_scan_toks_register_number();
6893 halfword v = tex_scan_integer(1, NULL);
6894 if (eq_value(register_attribute_location(i)) != v) {
6895 if (attrlist) {
6896 attrlist = tex_patch_attribute_list(attrlist, i, v);
6897 } else {
6898 attrlist = tex_copy_attribute_list_set(tex_current_attribute_list(), i, v);
6899 }
6900 }
6901 return attrlist;
6902}
6903 |