diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /systems/tex-extensions/clasen/glue |
Initial commit
Diffstat (limited to 'systems/tex-extensions/clasen/glue')
l--------- | systems/tex-extensions/clasen/glue/etex.bib | 1 | ||||
-rw-r--r-- | systems/tex-extensions/clasen/glue/glue-post-web2c.ch | 40 | ||||
-rw-r--r-- | systems/tex-extensions/clasen/glue/glue.ch | 677 | ||||
-rw-r--r-- | systems/tex-extensions/clasen/glue/glue.tex | 75 | ||||
-rw-r--r-- | systems/tex-extensions/clasen/glue/glueratio.patch | 15 |
5 files changed, 808 insertions, 0 deletions
diff --git a/systems/tex-extensions/clasen/glue/etex.bib b/systems/tex-extensions/clasen/glue/etex.bib new file mode 120000 index 0000000000..59519b0c14 --- /dev/null +++ b/systems/tex-extensions/clasen/glue/etex.bib @@ -0,0 +1 @@ +../etex.bib
\ No newline at end of file diff --git a/systems/tex-extensions/clasen/glue/glue-post-web2c.ch b/systems/tex-extensions/clasen/glue/glue-post-web2c.ch new file mode 100644 index 0000000000..ffa0ca7899 --- /dev/null +++ b/systems/tex-extensions/clasen/glue/glue-post-web2c.ch @@ -0,0 +1,40 @@ +% This change file has to be applied after the web2c change file +% to revert some changes which make assumtion on glue_ratio being +% real. Apart from the following change, they are all related to +% mltex. + +@x + { The Unix |pc| folks removed this restriction with a remark that + invalid bit patterns were vanishingly improbable, so we follow + their example without really understanding it. + |if abs(mem[p+glue_offset].int)<@'4000000 then print('?.?')| + |else| } + if fabs(g)>float_constant(20000) then + begin end; +@y +@z + +@x +@!base_slant,@!accent_slant:real; {amount of slant} +@y +@!base_slant,@!accent_slant:scaled; {amount of slant} +@z + +@x + base_slant:=slant(f)/float_constant(65536); +@^real division@> +@y + base_slant:=slant(f); +@z + +@x + delta:=round((base_width-accent_width)/float_constant(2)+ + base_height*base_slant-base_x_height*accent_slant); +@^real multiplication@> +@^real addition@> +@y + delta:=x_over_n(base_width-accent_width,2) + +xn_over_d(base_height,base_slant,unity) + -xn_over_d(base_x_height,accent_slant,unity); +@z + diff --git a/systems/tex-extensions/clasen/glue/glue.ch b/systems/tex-extensions/clasen/glue/glue.ch new file mode 100644 index 0000000000..a847ca31f9 --- /dev/null +++ b/systems/tex-extensions/clasen/glue/glue.ch @@ -0,0 +1,677 @@ +@x +@!interrupt:integer; {should \TeX\ pause for instructions?} +@!OK_to_interrupt:boolean; {should interrupts be observed?} + +@ @<Set init...@>= +interrupt:=0; OK_to_interrupt:=true; +@y +@!interrupt:integer; {should \TeX\ pause for instructions?} +@!OK_to_interrupt:boolean; {should interrupts be observed?} +@!two_to_the: array[0..30] of integer; {$|two_to_the|[k]=2^k$} + +@ @<Set init...@>= +interrupt:=0; OK_to_interrupt:=true; +two_to_the[0]:=1; +for i:=1 to 30 do two_to_the[i]:=two_to_the[i-1]+two_to_the[i-1]; +@z + +@x +@ When \TeX\ ``packages'' a list into a box, it needs to calculate the +proportionality ratio by which the glue inside the box should stretch +or shrink. This calculation does not affect \TeX's decision making, +so the precise details of rounding, etc., in the glue calculation are not +of critical importance for the consistency of results on different computers. + +We shall use the type |glue_ratio| for such proportionality ratios. +A glue ratio should take the same amount of memory as an +|integer| (usually 32 bits) if it is to blend smoothly with \TeX's +other data structures. Thus |glue_ratio| should be equivalent to +|short_real| in some implementations of \PASCAL. Alternatively, +it is possible to deal with glue ratios using nothing but fixed-point +arithmetic; see {\sl TUGboat \bf3},1 (March 1982), 10--27. (But the +routines cited there must be modified to allow negative glue ratios.) +@^system dependencies@> + +@d set_glue_ratio_zero(#) == #:=0.0 {store the representation of zero ratio} +@d set_glue_ratio_one(#) == #:=1.0 {store the representation of unit ratio} +@d float(#) == # {convert from |glue_ratio| to type |real|} +@d unfloat(#) == # {convert from |real| to type |glue_ratio|} +@d float_constant(#) == #.0 {convert |integer| constant to |real|} +@y +@ When \TeX\ ``packages'' a list into a box, it needs to calculate the +proportionality ratio by which the glue inside the box should stretch +or shrink. This calculation does not affect \TeX's decision making, +so the precise details of rounding, etc., in the glue calculation are not +of critical importance for the consistency of results on different computers. + +We shall use the type |glue_ratio| for such proportionality ratios. +A glue ratio should take the same amount of memory as an +|integer| (usually 32 bits) if it is to blend smoothly with \TeX's +other data structures. Thus |glue_ratio| should be equivalent to +|short_real| in some implementations of \PASCAL. Alternatively, +it is possible to deal with glue ratios using nothing but fixed-point +arithmetic; see {\sl TUGboat \bf3},1 (March 1982), 10--27. (But the +routines cited there must be modified to allow negative glue ratios.) + +This is what we do here. Our implementation stores |a+16| in the +low five bits, |b| in the next five bits and |c+@'100000| in the +next 17 bits of the integer |glue_ratio|. The procedures +|pack_glue_ratio| and |unpack_glue_ratio| are used to convert +to and from this format. A more efficient implementation would +inline these prodedures and use shifting. + +@d glue_ratio_zero == 33554480 {|pack_glue_ratio(16,1,0)=33554480|} +@d glue_ratio_one == 33556528 {|pack_glue_ratio(16,1,2)=33556528|} +@d set_glue_ratio_zero(#) == #:=glue_ratio_zero +@d set_glue_ratio_one(#) == #:=glue_ratio_one +@z + +@x +@!glue_ratio=real; {one-word representation of a glue expansion factor} +@y +@!glue_ratio=real; {one-word representation of a glue expansion factor} +@!glue_ratio=integer; {one-word representation of a glue expansion factor} + +@ Before we can state the glue-multiplication function |glue_mult|, we need +routines for packing and unpacking |glue_ratio|s. + +@p @!debug procedure check_range(l,h:integer; s:str_number; var v:integer); +begin + if v<l then begin + v:=l; + print_err(s); print(" too small"); + end else if v>h then begin + v:=h; + print_err(s); print(" too large"); + end; +end; +gubed + +function pack_glue_ratio(a,b,c:integer):glue_ratio; +begin + c:=c+@'100000; + @!debug + check_range(1,31,"pack_glue_ratio: a",a); + check_range(0,30,"pack_glue_ratio: b",b); + check_range(0,@'200000,"pack_glue_ratio: c",c); + gubed + pack_glue_ratio:=a+@'40*b+@'2000*c; +end; + +procedure unpack_glue_ratio(g:glue_ratio; var a,b,c:integer); +begin + c:=(g mod @'1000000000) div @'2000; + b:=(g mod @'2000) div @'40; + a:=g mod @'40; + @!debug + check_range(1,31,"unpack_glue_ratio: a",a); + check_range(0,30,"unpack_glue_ratio: b",b); + check_range(0,@'200000,"unpack_glue_ratio: c",c); + gubed + c:=c-@'100000; +end; + +function glue_mult(@!x:scaled;@!g:glue_ratio):integer; +var a,b,c:integer; +begin +unpack_glue_ratio(g,a,b,c); +if a>16 then x:=x div two_to_the[a-16] {right shift by |a| places} +else x:=x*two_to_the[16-a]; {left shift by |-a| places} +glue_mult:=(x*c) div two_to_the[b]; {right shift by |b| places} + end; {note that |b| may be as large as 30} + +@*Glue setting. +The |glue_fix| function computes |a|, |b|, and |c| by the method +explained in {\sl TUGboat \bf3},1 (March 1982), 10--27. This +implementation differs from the one given there in that it treats negative +values of |s| properly. To do so, we allow |c| to range from -@'100000 to +@'100000 and store it shifted by @'100000. + +|glue_fix| returns a |glue_ratio| approximation of |t/s|. + +@p function glue_fix(@!s,@!t,@!y:scaled):glue_ratio; +var @!a,@!b,@!c:integer; {components of the desired ratio} +@!k,@!h:integer; {$30-\lfloor\lg s\rfloor$, $30-\lfloor\lg t\rfloor$} +@!s0:integer; {original (unnormalized) value of |s|} +@!q,@!r,@!s1:integer; {quotient, remainder, divisor} +@!w:integer; {$2^l$, where $l=16-k$} +@!negative:boolean; +begin +negative:=false; +if s<0 then begin + negative:=true; + s:=-s; +end; +if y=0 then begin + print("glue_fix: y=0. Why?"); + glue_fix:=pack_glue_ratio(a+16,b,c); +end else begin +@<Normalize |s|, |t|, and |y|, computing |a|, |k|, and |h|@>; +if t<s then b:=15-a-k+h@+else b:=14-a-k+h; +if (b<0) or (b>30) then + begin if b<0 then + begin + print_err("Excessive glue"); +@.Excessive glue@> + help2("I can't work with sizes bigger than about 19 feet.")@/ + ("Proceed, with fingers crossed.");@/ + error; + end; + b:=0; c:=0; {make |f(x)| identically zero} + end +else begin if k>=16 then {easy case, $s_0<2^{15}$} + c:=(t div two_to_the[h-a-b]+s0-1) div s0 {here |1<=h-a-b<=k-14<=16|} + else @<Compute |c| by long division@>; + end; +if negative then c:=-c; +glue_fix:=pack_glue_ratio(a+16,b,c); +end; +end; + +@ @<Normalize |s|, |t|, and |y|, computing |a|, |k|, and |h|@>= +begin a:=15; k:=0; h:=0; s0:=s; +while y<@'10000000000 do {|y| is known to be positive} + begin decr(a); y:=y+y; + end; +while s<@'10000000000 do {|s| is known to be positive} + begin incr(k); s:=s+s; + end; +while t<@'10000000000 do {|t| is known to be positive} + begin incr(h); t:=t+t; + end; +end {now $2^{30}\le t=2^ht_0<2^{31}$ and $2^{30}\le s=2^ks_0<2^{31}$, + hence $d=k-h$ if $t/s<1$} + +@ @<Compute |c| by long division@>= +begin w:=two_to_the[16-k]; +s1:=s0 div w; +q:=t div s1; +r:=((t mod s1)*w)-((s0 mod w)*q); +if r>0 then + begin incr(q); r:=r-s0; + end +else while r<=-s0 do + begin decr(q); r:=r+s0; + end; +if a+b+k-h=15 then c:=(q+1) div 2 @+else c:=(q+3) div 4; +end +@z + +@x +@p @!debug procedure print_word(@!w:memory_word); + {prints |w| in all ways} +begin print_int(w.int); print_char(" ");@/ +print_scaled(w.sc); print_char(" ");@/ +print_scaled(round(unity*float(w.gr))); print_ln;@/ +@^real multiplication@> +print_int(w.hh.lh); print_char("="); print_int(w.hh.b0); print_char(":"); +print_int(w.hh.b1); print_char(";"); print_int(w.hh.rh); print_char(" ");@/ +print_int(w.qqqq.b0); print_char(":"); print_int(w.qqqq.b1); print_char(":"); +print_int(w.qqqq.b2); print_char(":"); print_int(w.qqqq.b3); +end; +gubed +@y +@p procedure print_gr(@!g:glue_ratio); {prints a glue multiplier} +var @!j:-29..31; {the amount to shift |c|} + a,b,c:integer; +begin +unpack_glue_ratio(g,a,b,c); +j:=32-a-b; +while j>15 do + begin print("2x"); decr(j); {indicate multiples of 2 for BIG cases} + end; +if j<0 then print_scaled(c div two_to_the[-j]) {shift right} +else print_scaled(c*two_to_the[j]); {shift left} +end; + +@!debug procedure print_word(@!w:memory_word); + {prints |w| in all ways} +begin print_int(w.int); print_char(" ");@/ +print_scaled(w.sc); print_char(" ");@/ +print_gr(w.gr); print_ln;@/ +print_int(w.hh.lh); print_char("="); print_int(w.hh.b0); print_char(":"); +print_int(w.hh.b1); print_char(";"); print_int(w.hh.rh); print_char(" ");@/ +print_int(w.qqqq.b0); print_char(":"); print_int(w.qqqq.b1); print_char(":"); +print_int(w.qqqq.b2); print_char(":"); print_int(w.qqqq.b3); +end; +gubed +@z + +@x +@p procedure show_node_list(@!p:integer); {prints a node list symbolically} +label exit; +var n:integer; {the number of items already printed at this level} +@!g:real; {a glue ratio, as a floating point number} +@y +@p procedure show_node_list(@!p:integer); {prints a node list symbolically} +label exit; +var n:integer; {the number of items already printed at this level} +@!g:glue_ratio; {a glue ratio, as a floating point number} +a,b,c,j:integer; +@z + +@x +@ The code will have to change in this place if |glue_ratio| is +a structured type instead of an ordinary |real|. Note that this routine +should avoid arithmetic errors even if the |glue_set| field holds an +arbitrary random value. The following code assumes that a properly +formed nonzero |real| number has absolute value $2^{20}$ or more when +it is regarded as an integer; this precaution was adequate to prevent +floating point underflow on the author's computer. +@^system dependencies@> +@^dirty \PASCAL@> + +@<Display the value of |glue_set(p)|@>= +g:=float(glue_set(p)); +if (g<>float_constant(0))and(glue_sign(p)<>normal) then + begin print(", glue set "); + if glue_sign(p)=shrinking then print("- "); + if abs(mem[p+glue_offset].int)<@'4000000 then print("?.?") + else if abs(g)>float_constant(20000) then + begin if g>float_constant(0) then print_char(">") + else print("< -"); + print_glue(20000*unity,glue_order(p),0); + end + else print_glue(round(unity*g),glue_order(p),0); +@^real multiplication@> + end +@y +@ The code has been changed here, since |glue_ratio| is no longer |real|. +Note that this routine should avoid arithmetic errors even if the |glue_set| +field holds an arbitrary random value. + +@<Display the value of |glue_set(p)|@>= +if (glue_ratio_zero<>glue_set(p))and(glue_sign(p)<>normal) then begin + print(", glue set "); + if glue_sign(p)=shrinking then print("- "); + if abs(mem[p+glue_offset].int)<@'4000000 then print("?.?") + else if abs(g)>float_constant(20000) then + begin end; + print_gr(glue_set(p)); + case glue_order(p) of + normal: do_nothing; + fil: print("fil"); + fill: print("fill"); + filll: print("filll"); + othercases print("foul") + endcases +end; +@z + +@x +@!glue_temp:real; {glue value before rounding} +@y +@!glue_temp:scaled; {glue value before rounding} +@z + +@x +@ @d vet_glue(#)== glue_temp:=#; + if glue_temp>float_constant(1000000000) then + glue_temp:=float_constant(1000000000) + else if glue_temp<-float_constant(1000000000) then + glue_temp:=-float_constant(1000000000) +@y +@ @d vet_glue(#)== glue_temp:=#; + if glue_temp>1000000000 then glue_temp:=1000000000 + else if glue_temp<-1000000000 then glue_temp:=-1000000000 +@z + +@x +@<Move right or output leaders@>= +begin g:=glue_ptr(p); rule_wd:=width(g); +if g_sign<>normal then + begin if g_sign=stretching then + begin if stretch_order(g)=g_order then + begin vet_glue(float(glue_set(this_box))*stretch(g)); +@^real multiplication@> + rule_wd:=rule_wd+round(glue_temp); + end; + end + else if shrink_order(g)=g_order then + begin vet_glue(float(glue_set(this_box))*shrink(g)); + rule_wd:=rule_wd-round(glue_temp); + end; + end; +@y +@<Move right or output leaders@>= +begin g:=glue_ptr(p); rule_wd:=width(g); +if g_sign<>normal then + begin if g_sign=stretching then + begin if stretch_order(g)=g_order then + begin + vet_glue(glue_mult(stretch(g),glue_set(this_box))); + rule_wd:=rule_wd+glue_temp; + end; + end + else if shrink_order(g)=g_order then + begin + vet_glue(glue_mult(shrink(g),glue_set(this_box))); + rule_wd:=rule_wd-glue_temp; + end; + end; +@z + +@x +@!glue_temp:real; {glue value before rounding} +@y +@!glue_temp:scaled; {glue value before rounding} +@z + +@x +@ @<Move down or output leaders@>= +begin g:=glue_ptr(p); rule_ht:=width(g); +if g_sign<>normal then + begin if g_sign=stretching then + begin if stretch_order(g)=g_order then + begin vet_glue(float(glue_set(this_box))*stretch(g)); +@^real multiplication@> + rule_ht:=rule_ht+round(glue_temp); + end; + end + else if shrink_order(g)=g_order then + begin vet_glue(float(glue_set(this_box))*shrink(g)); + rule_ht:=rule_ht-round(glue_temp); + end; + end; +@y +@ @<Move down or output leaders@>= +begin g:=glue_ptr(p); rule_ht:=width(g); +if g_sign<>normal then + begin if g_sign=stretching then + begin if stretch_order(g)=g_order then + begin + vet_glue(glue_mult(stretch(g),glue_set(this_box))); + rule_ht:=rule_ht+glue_temp; + end; + end + else if shrink_order(g)=g_order then + begin + vet_glue(glue_mult(shrink(g),glue_set(this_box))); + rule_ht:=rule_ht-glue_temp; + end; + end; +@z + +@x +@!total_stretch, @!total_shrink: array[glue_ord] of scaled; + {glue found by |hpack| or |vpack|} +@y +@!total_stretch, @!total_shrink, @!max_stretch, @!max_shrink: + array[glue_ord] of scaled; {glue found by |hpack| or |vpack|} +@z + +@x +@ @<Clear dimensions to zero@>= +d:=0; x:=0; +total_stretch[normal]:=0; total_shrink[normal]:=0; +total_stretch[fil]:=0; total_shrink[fil]:=0; +total_stretch[fill]:=0; total_shrink[fill]:=0; +total_stretch[filll]:=0; total_shrink[filll]:=0 +@y +@ @<Clear dimensions to zero@>= +d:=0; x:=0; +total_stretch[normal]:=0; total_shrink[normal]:=0; +total_stretch[fil]:=0; total_shrink[fil]:=0; +total_stretch[fill]:=0; total_shrink[fill]:=0; +total_stretch[filll]:=0; total_shrink[filll]:=0; +max_stretch[normal]:=0; max_shrink[normal]:=0; +max_stretch[fil]:=0; max_shrink[fil]:=0; +max_stretch[fill]:=0; max_shrink[fill]:=0; +max_stretch[filll]:=0; max_shrink[filll]:=0 +@z + +@x +@ @<Incorporate glue into the horizontal totals@>= +begin g:=glue_ptr(p); x:=x+width(g);@/ +o:=stretch_order(g); total_stretch[o]:=total_stretch[o]+stretch(g); +o:=shrink_order(g); total_shrink[o]:=total_shrink[o]+shrink(g); +@y +@ @<Incorporate glue into the horizontal totals@>= +begin g:=glue_ptr(p); x:=x+width(g);@/ +o:=stretch_order(g); total_stretch[o]:=total_stretch[o]+stretch(g); +if abs(stretch(g))>max_stretch[o] then max_stretch[o]:=abs(stretch(g)); +o:=shrink_order(g); total_shrink[o]:=total_shrink[o]+shrink(g); +if abs(shrink(g))>max_shrink[o] then max_shrink[o]:=abs(shrink(g)); +@z + +@x +@ @<Determine horizontal glue stretch setting...@>= +begin @<Determine the stretch order@>; +glue_order(r):=o; glue_sign(r):=stretching; +if total_stretch[o]<>0 then glue_set(r):=unfloat(x/total_stretch[o]) +@^real division@> +else begin glue_sign(r):=normal; + set_glue_ratio_zero(glue_set(r)); {there's nothing to stretch} + end; +@y +@ @<Determine horizontal glue stretch setting...@>= +begin @<Determine the stretch order@>; +glue_order(r):=o; glue_sign(r):=stretching; +if total_stretch[o]<>0 then + glue_set(r):=glue_fix(total_stretch[o],x,max_stretch[o]) +else begin glue_sign(r):=normal; + glue_set(r):=glue_ratio_zero; {there's nothing to stretch} + end; +@z + +@x +@ @<Determine horizontal glue shrink setting...@>= +begin @<Determine the shrink order@>; +glue_order(r):=o; glue_sign(r):=shrinking; +if total_shrink[o]<>0 then glue_set(r):=unfloat((-x)/total_shrink[o]) +@^real division@> +@y +@ @<Determine horizontal glue shrink setting...@>= +begin @<Determine the shrink order@>; +glue_order(r):=o; glue_sign(r):=shrinking; +if total_shrink[o]<>0 then + glue_set(r):=glue_fix(total_shrink[o],-x,max_shrink[o]) +@z + +@x +@ @<Incorporate glue into the vertical totals@>= +begin x:=x+d; d:=0;@/ +g:=glue_ptr(p); x:=x+width(g);@/ +o:=stretch_order(g); total_stretch[o]:=total_stretch[o]+stretch(g); +o:=shrink_order(g); total_shrink[o]:=total_shrink[o]+shrink(g); +@y +@ @<Incorporate glue into the vertical totals@>= +begin x:=x+d; d:=0;@/ +g:=glue_ptr(p); x:=x+width(g);@/ +o:=stretch_order(g); total_stretch[o]:=total_stretch[o]+stretch(g); +if abs(stretch(g))>max_stretch[o] then max_stretch[o]:=abs(stretch(g)); +o:=shrink_order(g); total_shrink[o]:=total_shrink[o]+shrink(g); +if abs(shrink(g))>max_shrink[o] then max_shrink[o]:=abs(shrink(g)); +@z + +@x +@ @<Determine vertical glue stretch setting...@>= +begin @<Determine the stretch order@>; +glue_order(r):=o; glue_sign(r):=stretching; +if total_stretch[o]<>0 then glue_set(r):=unfloat(x/total_stretch[o]) +@^real division@> +@y +@ @<Determine vertical glue stretch setting...@>= +begin @<Determine the stretch order@>; +glue_order(r):=o; glue_sign(r):=stretching; +if total_stretch[o]<>0 then + glue_set(r):=glue_fix(total_stretch[o],x,max_stretch[o]) +@z + +@x +@ @<Determine vertical glue shrink setting...@>= +begin @<Determine the shrink order@>; +glue_order(r):=o; glue_sign(r):=shrinking; +if total_shrink[o]<>0 then glue_set(r):=unfloat((-x)/total_shrink[o]) +@^real division@> +@y +@ @<Determine vertical glue shrink setting...@>= +begin @<Determine the shrink order@>; +glue_order(r):=o; glue_sign(r):=shrinking; +if total_shrink[o]<>0 then + glue_set(r):=glue_fix(total_shrink[o],-x,max_shrink[o]) +@z + +@x +@ @<Append tabskip glue and an empty box to list |u|...@>= +s:=link(s); v:=glue_ptr(s); link(u):=new_glue(v); u:=link(u); +subtype(u):=tab_skip_code+1; t:=t+width(v); +if glue_sign(p)=stretching then + begin if stretch_order(v)=glue_order(p) then + t:=t+round(float(glue_set(p))*stretch(v)); +@^real multiplication@> + end +else if glue_sign(p)=shrinking then + begin if shrink_order(v)=glue_order(p) then + t:=t-round(float(glue_set(p))*shrink(v)); + end; +@y +@ @<Append tabskip glue and an empty box to list |u|...@>= +s:=link(s); v:=glue_ptr(s); link(u):=new_glue(v); u:=link(u); +subtype(u):=tab_skip_code+1; t:=t+width(v); +if glue_sign(p)=stretching then + begin if stretch_order(v)=glue_order(p) then + t:=t+glue_mult(stretch(v),glue_set(p)); + end +else if glue_sign(p)=shrinking then + begin if shrink_order(v)=glue_order(p) then + t:=t-glue_mult(shrink(v),glue_set(p)); + end; +@z + +@x +@ @<Make the unset node |r| into an |hlist_node| of width |w|...@>= +begin height(r):=height(q); depth(r):=depth(q); +if t=width(r) then + begin glue_sign(r):=normal; glue_order(r):=normal; + set_glue_ratio_zero(glue_set(r)); + end +else if t>width(r) then + begin glue_sign(r):=stretching; + if glue_stretch(r)=0 then set_glue_ratio_zero(glue_set(r)) + else glue_set(r):=unfloat((t-width(r))/glue_stretch(r)); +@^real division@> + end +else begin glue_order(r):=glue_sign(r); glue_sign(r):=shrinking; + if glue_shrink(r)=0 then set_glue_ratio_zero(glue_set(r)) + else if (glue_order(r)=normal)and(width(r)-t>glue_shrink(r)) then + set_glue_ratio_one(glue_set(r)) + else glue_set(r):=unfloat((width(r)-t)/glue_shrink(r)); + end; +width(r):=w; type(r):=hlist_node; +end +@y +@ @<Make the unset node |r| into an |hlist_node| of width |w|...@>= +begin height(r):=height(q); depth(r):=depth(q); +if t=width(r) then + begin glue_sign(r):=normal; glue_order(r):=normal; + glue_set(r):=glue_ratio_zero; + end +else if t>width(r) then + begin glue_sign(r):=stretching; + if glue_stretch(r)=0 then glue_set(r):=glue_ratio_zero + else + glue_set(r):=glue_fix(glue_stretch(r),t-width(r),abs(glue_stretch(r)/2)); + end +else begin glue_order(r):=glue_sign(r); glue_sign(r):=shrinking; + if glue_shrink(r)=0 then glue_set(r):=glue_ratio_zero + else if (glue_order(r)=normal)and(width(r)-t>glue_shrink(r)) then + glue_set(r):=glue_ratio_one + else + glue_set(r):=glue_fix(glue_shrink(r),width(r)-t,abs(glue_shrink(r)/2)); + end; +width(r):=w; type(r):=hlist_node; +end +@z + +@x +@ @<Make the unset node |r| into a |vlist_node| of height |w|...@>= +begin width(r):=width(q); +if t=height(r) then + begin glue_sign(r):=normal; glue_order(r):=normal; + set_glue_ratio_zero(glue_set(r)); + end +else if t>height(r) then + begin glue_sign(r):=stretching; + if glue_stretch(r)=0 then set_glue_ratio_zero(glue_set(r)) + else glue_set(r):=unfloat((t-height(r))/glue_stretch(r)); +@^real division@> + end +else begin glue_order(r):=glue_sign(r); glue_sign(r):=shrinking; + if glue_shrink(r)=0 then set_glue_ratio_zero(glue_set(r)) + else if (glue_order(r)=normal)and(height(r)-t>glue_shrink(r)) then + set_glue_ratio_one(glue_set(r)) + else glue_set(r):=unfloat((height(r)-t)/glue_shrink(r)); + end; +height(r):=w; type(r):=vlist_node; +end +@y +@ @<Make the unset node |r| into a |vlist_node| of height |w|...@>= +begin width(r):=width(q); +if t=height(r) then + begin glue_sign(r):=normal; glue_order(r):=normal; + glue_set(r):=glue_ratio_zero; + end +else if t>height(r) then + begin glue_sign(r):=stretching; + if glue_stretch(r)=0 then glue_set(r):=glue_ratio_zero + else + glue_set(r):=glue_fix(glue_stretch(r),t-height(r),abs(glue_stretch(r)/2)); + end +else begin glue_order(r):=glue_sign(r); glue_sign(r):=shrinking; + if glue_shrink(r)=0 then glue_set(r):=glue_ratio_zero + else if (glue_order(r)=normal)and(height(r)-t>glue_shrink(r)) then + glue_set(r):=glue_ratio_one + else + glue_set(r):=glue_fix(glue_shrink(r),height(r)-t,abs(glue_shrink(r)/2)); + end; +height(r):=w; type(r):=vlist_node; +end +@z + +@x +procedure make_accent; +var s,@!t: real; {amount of slant} +@!p,@!q,@!r:pointer; {character, box, and kern nodes} +@!f:internal_font_number; {relevant font} +@!a,@!h,@!x,@!w,@!delta:scaled; {heights and widths, as explained above} +@!i:four_quarters; {character information} +begin scan_char_num; f:=cur_font; p:=new_character(f,cur_val); +if p<>null then + begin x:=x_height(f); s:=slant(f)/float_constant(65536); +@^real division@> +@y +procedure make_accent; +var @!s,@!t:scaled; {amount of slant} +@!p,@!q,@!r:pointer; {character, box, and kern nodes} +@!f:internal_font_number; {relevant font} +@!a,@!h,@!x,@!w,@!delta:scaled; {heights and widths, as explained above} +@!i:four_quarters; {character information} +begin scan_char_num; f:=cur_font; p:=new_character(f,cur_val); +if p<>null then + begin x:=x_height(f); s:=slant(f); +@z + +@x +@<Append the accent with appropriate kerns...@>= +begin t:=slant(f)/float_constant(65536); +@^real division@> +i:=char_info(f)(character(q)); +w:=char_width(f)(i); h:=char_height(f)(height_depth(i)); +if h<>x then {the accent must be shifted up or down} + begin p:=hpack(p,natural); shift_amount(p):=x-h; + end; +delta:=round((w-a)/float_constant(2)+h*t-x*s); +@^real multiplication@> +@^real addition@> +@y +@<Append the accent with appropriate kerns...@>= +begin t:=slant(f); +i:=char_info(f)(character(q)); +w:=char_width(f)(i); h:=char_height(f)(height_depth(i)); +if h<>x then {the accent must be shifted up or down} + begin p:=hpack(p,natural); shift_amount(p):=x-h; + end; +delta:=x_over_n(w-a,2)+xn_over_d(h,t,unity)-xn_over_d(x,s,unity); +@z + diff --git a/systems/tex-extensions/clasen/glue/glue.tex b/systems/tex-extensions/clasen/glue/glue.tex new file mode 100644 index 0000000000..d124bf32b0 --- /dev/null +++ b/systems/tex-extensions/clasen/glue/glue.tex @@ -0,0 +1,75 @@ +\documentclass[preprint]{ltugboat} +\usepackage{shortvrb} +\usepackage{url} + +\providecommand{\meta}[1]{\ensuremath{\langle\textit{#1}\rangle}} +\makeatletter +\providecommand{\eTeX}{$\m@th\varepsilon$-\TeX} +\makeatother +\hyphenation{pa-ra-me-ter} + +\emergencystretch=4mm +\title{Purging \TeX\ from floating-point arithmetic} +\author{Matthias Clasen} +%\address{} +\netaddress{maclas@gmx.de} +\setcounter{page}{1} + +\begin{document} +\maketitle +\MakeShortVerb{\|} + +\section{Introduction} + +\TeX\ uses machine-dependent floating-point arithmetic for its +internal glue computations. This is the reason why a (undoubtly very useful) +general |\lastnode| command cannot be added to \TeX\ without risking +the portability of documents. + +A long time ago, Knuth demonstrated how to implement \TeX's glue computations +in fixed-point arithmetic\cite{Knuth:82,Knuth:91}. Knuth mentions that his +code would have to be slightly generalized before it can be used in \TeX. To +my knowledge, this has not been done before. + +After applying my change file, |tex.web| no longer contains any +variables of type |real|, proving that I was successful in removing all +floating-point arithmetic from \TeX. I have not implemented the (now possible) +|\lastnode| primitive. + +\section{Implementation} + +The changes to \TeX{} the program sketched above are realized in the +change file |glue.ch|, which is a rewrite of Knuth's |glue.web|. + +\section{Installation} + + The change files are written for \TeX~3.1459. But it should need only + cosmetic changes to get them to work with other versions of \TeX3. + + To make the change files for \TeX{} work, you have to apply the change file + |pre.ch| first. I have only tried these files with |web2c|, and + for that you need to surround the |web2c| change file with |pre-web2c.ch| and + |post-web2c.ch|. You also need the additional change file + |glue-post-web2c.ch| and the patch file |glueratio.patch|. + The patch file is necessary, since |web2c| fixes the type |glueratio| + to be |double| in a file which is not subject to the |web| translation + process. The patch file changes this to the new type |glueratio| if + the |cpp| macro |HAVE_GLUERATIO_TYPE| is defined. + + All this boils down to the command line + +\begin{verbatim} +mv tex.ch tex.ch.orig +tie -c tex.ch tex.web pre.ch glue.ch \ + pre-web2c.ch tex.ch.orig \ + post-web2c.ch glue-post-web2c.ch +patch < glueratio.ch +export XCFLAGS=-DHAVE_GLUERATIO_TYPE +\end{verbatim} + + \makesignature + + \bibliographystyle{plain} + \bibliography{etex} + +\end{document} diff --git a/systems/tex-extensions/clasen/glue/glueratio.patch b/systems/tex-extensions/clasen/glue/glueratio.patch new file mode 100644 index 0000000000..d8064e18a7 --- /dev/null +++ b/systems/tex-extensions/clasen/glue/glueratio.patch @@ -0,0 +1,15 @@ +--- texmfmp.h.orig Thu Jul 23 18:36:40 1998 ++++ texmfmp.h Thu Jul 23 18:37:21 1998 +@@ -86,10 +86,12 @@ + + This type is set automatically to `float' by configure if a small TeX + is built. */ ++#ifndef HAVE_GLUERATIO_TYPE + #ifndef GLUERATIO_TYPE + #define GLUERATIO_TYPE double + #endif + typedef GLUERATIO_TYPE glueratio; ++#endif + + extern void setupcharset P1H(void); + |