/* C-TeX function and variable bindings */ /* * Copyright (c) 1987 University of Maryland Department of Computer Science. * All rights reserved. Permission to copy for any purpose is hereby granted * so long as this copyright notice remains intact. */ #ifdef StringSizeof /* * If StringSizeof is defined, we assume that (sizeof "string_const") is * equal to (strlen("string_const") + 1); see the DefXXX macros below. */ #endif /* * Here are the various flags that can be in the b_flags field of a struct * BoundName. */ #define BIsSpecial 1 /* a special int or dimen, or a font; assignments to these are always global */ #define BIsOuter 2 /* \outer, may not appear in macro def'n */ #define BIsLong 4 /* \long, may contain \outer s anyway */ #define BIsUndef 8 /* not defined anymore - used when a def'n local to a group is destroyed by exiting the group */ /* * SPECIAL * 1. Integers: * \spacefactor \prevgraf \deadcycles \insertpenalties * 2. Dimens: * \prevdepth \pagegoal \pagetotal \pagestretch \pagefilstretch * \pagefillstretch \pagefilllstretch \pageshrink \pagedepth */ enum BindingKind { ProcBound, VarBound, IntBound, DimenBound, CodeBound, FontBound }; union BindUnion { int (*b_proc)(); /* iff ProcBound */ struct node *b_var; /* iff VarBound */ i32 *b_int; /* iff IntBound */ scaled *b_dimen; /* iff DimenBound */ i32 b_code; /* iff CodeBound */ struct FontInfo *b_font; /* iff FontBound */ }; /* * The basic entity of C-TeX is the `BoundName'. It is either a wired-in * procedure (e.g. \let, \def, \vskip) or variable (\hsize, \parskip), or a * user-defined macro/variable/whatnot. These are indistinguishable from * one another (except that only wired procedures are ProcBound). * * There are also `CodeBound' things, which have no b_name and no b_flags. * In fact, they are really BoundNameCodes, but they need similar treatment, * so they get a similar structure. */ struct BoundName { enum BindingKind b_binding; /* the kind of thing it is */ union BindUnion b_bound; /* the current binding */ struct SavedVal *b_AfterGroupRst; /* The saved value for restoration after the current group. This is a pointer into the current AfterGroupRst list. */ struct string b_name; /* the name of this thing */ int b_flags; /* various flags */ }; /* * \catcodes, \lccodes, etc are CodeBound, and are really arrays of these: */ struct BoundNameCode { enum BindingKind b_binding; union BindUnion b_bound; struct SavedVal *b_AfterGroupRst; }; /* * Saved values (changes that are local to a group) are stored in a doubly * linked list; this is so that constructs like * {\advance\count0 by1 \global\advance\count0 by1} * can easily delete restorations that are no longer needed (having been * overridden by a \global operation). In other words, we never have * any `save stack buildup'. This requires the `spaghetti' below: a * current group level (so if b_AfterGroupRst is set, we can tell whether * the saved val is for this level) and moreover any inner saves for this * BoundName. * * To illustrate what is going on, suppose that we have count1==0. Now we * begin group number 1, then 2. Now we set count1 to 5, and since it has * no AfterGroupRst we save the 0 at level 2. Now we increment count1, and * since it has an AfterGroupRst, we check the level. It is 2; everything * is fine, and count1 is set to 6. Now we begin group 3, and again increment * count1. The level is 2, so we make a new SavedVal and set its level to * 3. (We now have count1==7, save==6 when exiting level 3, save==0 when * exiting 2.) Now the user does a \global\count1=42, so alas!, all those * saved values are useless. To get rid of them, we delete the current * SavedVal, and its inner, and its inner's inner, and so forth, then clear * the AfterGroupRst pointer. Voila! A global \count1, set to 42. * * Note that we save CodeBound changes here too. Since CodeBound objects * have no flags, some care is needed during restoration. */ struct SavedVal { int sv_level; /* the level to which this belongs */ struct SavedVal *sv_next; /* linked list */ struct SavedVal *sv_prev; /* or more precisely, queue */ struct SavedVal *sv_inner; /* the inner saved value (from the previous group that saved this) */ union BindUnion sv_val; /* the saved value (note that saved values are always the same type as current values---i.e., types are fixed) */ struct BoundName *sv_b; /* the BoundName to which it belongs */ int sv_flags; /* the saved b_flags (if applicable) */ }; struct BoundName **NewNames; /* during initialization, each internal BoundName is stashed in the table to which this points */ int CurrentGroup; /* the group level number of the current group; incremented for { and decremented for }, etc */ struct SavedVal *AfterGroupRst;/* the current list for restoring locally modified BoundNames */ /* * The following hackery will make the compiler complain in the event * of a dropped semicolon, without making lint complain. */ #ifdef lint #define do_nothing (void) rand() #else #define do_nothing 0 #endif /* * Save a binding. */ #define SaveB(b) \ if ((b)->b_AfterGroupRst == NULL || \ (b)->b_AfterGroupRst->sv_level != CurrentGroup) \ DoSave(b); \ else \ do_nothing /* * Undo a save. */ #define UnSaveB(b) \ if ((b)->b_AfterGroupRst) \ DoUnsave(b); \ else \ do_nothing #ifdef StringSizeof #define InitStrAndLen(str,cstr) (str.s_len = sizeof cstr-1, str.s_str = cstr) #else #define InitStrAndLen(str,cstr) (str.s_len = strlen(str.s_str = cstr)) #endif #define SetBFlags(f) NewNames[-1].b_flags |= (f) #define DefIntVar(addr, name) { \ static struct BoundName _b; \ InitStrAndLen(_b.b_name, name); \ _b.b_binding = IntBound; \ _b.b_bound.b_int = addr; \ *NewNames++ = &_b; \ } #define DefDimenVar(addr, name) { \ static struct BoundName _b; \ InitStrAndLen(_b.b_name, name); \ _b.b_binding = DimenBound; \ _b.b_bound.b_dimen = addr; \ *NewNames++ = &_b; \ } #define DefProc(name, proc, flags) { \ static struct BoundName _b; \ InitStrAndLen(_b.b_name, name); \ _b.b_binding = ProcBound; \ _b.b_bound.b_proc = proc; \ _b.b_bound.b_flags = flags; \ *NewNames++ = &_b; \ }