@= f:=1; repeat be_careful:=p-q; p:=be_careful+p; if p>=0 then f:=f+f+1 else begin double(f); p:=p+q; end; until f>=fraction_one; be_careful:=p-q; if be_careful+p>=0 then incr(f) @y We have replaced the \PASCAL\ version of |make_fraction| with either a C or assembly language equivalent for efficiency. @ This section was deleted when |make_fraction| was removed. @z %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % [7.109,110,111] And ditto for take_fraction. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @x @p function take_fraction(@!q:integer;@!f:fraction):integer; var @!p:integer; {the fraction so far} @!negative:boolean; {should the result be negated?} @!n:integer; {additional multiple of $q$} @!be_careful:integer; {disables certain compiler optimizations} begin @ =0| and |q>0|@>; if f ; be_careful:=n-el_gordo; if be_careful+p>0 then begin arith_error:=true; n:=el_gordo-p; end; if negative then take_fraction:=-(n+p) else take_fraction:=n+p; end; @ @ =0| and |q>0|@>= if f>=0 then negative:=false else begin negate(f); negative:=true; end; if q<0 then begin negate(q); negative:=not negative; end; @ The invariant relations in this case are (i)~$\lfloor(qf+p)/2^k\rfloor =\lfloor qf_0/2^{28}+{1\over2}\rfloor$, where $k$ is an integer and $f_0$ is the original value of~$f$; (ii)~$2^k\L f<2^{k+1}$. @^inner loop@> @ = p:=fraction_half; {that's $2^{27}$; the invariants hold now with $k=28$} if q =0| and |q>0|@>= if f>=0 then negative:=false else begin negate(f); negative:=true; end; if q<0 then begin negate(q); negative:=not negative; end; @ This section was deleted when |take_fraction| was replaced by an external routine. @z %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % [9.153] Make it easy to build a bigger Metafont. (Nothing is changed % in the basic version.) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @x @d min_quarterword=0 {smallest allowable value in a |quarterword|} @d max_quarterword=255 {largest allowable value in a |quarterword|} @d min_halfword==0 {smallest allowable value in a |halfword|} @d max_halfword==65535 {largest allowable value in a |halfword|} @y @d min_quarterword=0 {smallest allowable value in a |quarterword|} @d max_quarterword=255 {largest allowable value in a |quarterword|} @d min_halfword==0 {smallest allowable value in a |halfword|} @d max_halfword==65535 {largest allowable value in a |halfword|} @z %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % [??] Efficiency in C. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @x @ The operation of subtracting |min_halfword| occurs rather frequently in \MF, so it is convenient to abbreviate this operation by using the macro |ho| defined here. \MF\ will run faster with respect to compilers that don't optimize the expression `|x-0|', if this macro is simplified in the obvious way when |min_halfword=0|. Similarly, |qi| and |qo| are used for input to and output from quarterwords. @^system dependencies@> @d ho(#)==#-min_halfword {to take a sixteen-bit item from a halfword} @d qo(#)==#-min_quarterword {to read eight bits from a quarterword} @d qi(#)==#+min_quarterword {to store eight bits in a quarterword} @y @ The operation of subtracting |min_halfword| occurs rather frequently in \MF, so it is convenient to abbreviate this operation by using the macro |ho| defined here. \MF\ will run faster with respect to compilers that don't optimize the expression `|x-0|', if this macro is simplified in the obvious way when |min_halfword=0|. Similarly, |qi| and |qo| are used for input to and output from quarterwords. We need not do this in C, since the min_xxx values are all zero, and we can't depend on most C compilers to optimize this. @^system dependencies@> @d ho(#)==# @d qo(#)==# @d qi(#)==# @z %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % [??] Put the memory structure into an include file; it's too hard % to translate automatically. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @x @!two_halves = packed record@;@/ @!rh:halfword; case two_choices of 1: (@!lh:halfword); 2: (@!b0:quarterword; @!b1:quarterword); end; @!four_quarters = packed record@;@/ @!b0:quarterword; @!b1:quarterword; @!b2:quarterword; @!b3:quarterword; end; @!memory_word = record@;@/ case three_choices of 1: (@!int:integer); 2: (@!hh:two_halves); 3: (@!qqqq:four_quarters); end; @y @=#include "memory.h";@> @z %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % [??] Fix an unsigned/signed problem in getnode. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @x if r>p+1 then @ ; @y if r>toint(p+1) then @ ; @z %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % [11.178] Change the word `free' so that it doesn't conflict with the % standard C library routine of the same name. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @x been included. (You may want to decrease the size of |mem| while you @^debugging@> are debugging.) @y been included. (You may want to decrease the size of |mem| while you @^debugging@> are debugging.) @d free==free_arr @z %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % [??] Eliminate two unsigned comparisons to zero. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @x repeat if (p>=lo_mem_max)or(p =lo_mem_max)or(rlink(p) =lo_mem_max) then clobbered:=true else if (rlink(p)>=lo_mem_max) then clobbered:=true @z %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % [12.194] fix_date_and_time %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @x @ The following procedure, which is called just before \MF\ initializes its input and output, establishes the initial values of the date and time. @^system dependencies@> Since standard \PASCAL\ cannot provide such information, something special is needed. The program here simply specifies July 4, 1776, at noon; but users probably want a better approximation to the truth. Note that the values are |scaled| integers. Hence \MF\ can no longer be used after the year 32767. @p procedure fix_date_and_time; begin internal[time]:=12*60*unity; {minutes since midnight} internal[day]:=4*unity; {fourth day of the month} internal[month]:=7*unity; {seventh month of the year} internal[year]:=1776*unity; {Anno Domini} end; @y @ The following procedure, which is called just before \MF\ initializes its input and output, establishes the initial values of the date and time. It is calls an externally defined |date_and_time|, even though it could be done from Pascal. The external procedure also sets up interrupt catching. @^system dependencies@> Note that the values are |scaled| integers. Hence \MF\ can no longer be used after the year 32767. @p procedure fix_date_and_time; begin date_and_time(internal[time],internal[day],internal[month],internal[year]); internal[time] := internal[time] * unity; internal[day] := internal[day] * unity; internal[month] := internal[month] * unity; internal[year] := internal[year] * unity; end; @z %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % [12.199] Allow and