home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / APPS / lout2.lzh / LOUT2 / DOC / TR.IMPL / s2.4 < prev    next >
Text File  |  1994-01-25  |  12KB  |  346 lines

  1. @SubSection
  2.     @Tag { objects.impl }
  3.     @Title { Implementation of objects and concatenation }
  4. @Begin
  5. @PP
  6. In this section we discuss the implementation of objects and concatenation,
  7. and especially mark alignment.  The first step is to use an operator
  8. precedence parser to convert input such as
  9. @ID @Code "a  |0.5i  b  /0.2i  c  |  d"
  10. into parse trees such as
  11. @ID @Eq {
  12. @Fig {
  13. @Tree {
  14. @Node @FCircle fraction
  15. @FirstSub {
  16.    @Node @FCircle bar
  17.    @FirstSub { @Node @FCircle a }
  18.    @NextSub  { @Node @FEllipse 0.5i }
  19.    @NextSub  { @Node @FCircle b }
  20. }
  21. @NextSub { @Node @FEllipse 0.2i }
  22. @NextSub {
  23.    @Node @FCircle bar
  24.    @FirstSub { @Node @FCircle c }
  25.    @NextSub  { @Node @FCircle   }
  26.    @NextSub  { @Node @FCircle d }
  27. }
  28. }
  29. }
  30. }
  31. Missing objects are replaced by empty objects, and sequences of
  32. concatenation operators are consolidated:
  33. @ID @Eq {
  34. @Fig {
  35. @Tree {
  36. @Node @FCircle bar
  37. @FirstSub { @Node @FCircle a }
  38. @NextSub { @Node @FEllipse 0.2i }
  39. @NextSub {
  40.    @Node @FCircle bar
  41.    @FirstSub { @Node @FCircle c     }
  42.    @NextSub  { @Node @FEllipse 0.3i }
  43.    @NextSub  { @Node @FCircle d     }
  44. }
  45. }
  46. }
  47. &2m ==> &2m
  48. @Fig {
  49. @Tree {
  50. @Node @FCircle bar
  51. @FirstSub { @Node @FCircle a     }
  52. @NextSub  { @Node @FEllipse 0.2i }
  53. @NextSub  { @Node @FCircle c     }
  54. @NextSub  { @Node @FEllipse 0.3i }
  55. @NextSub  { @Node @FCircle d     }
  56. }
  57. }
  58. }
  59. to make manifest their associativity and reduce the depth of the tree
  60. for efficiency later.
  61. @PP
  62. The required semantic information is the size of each subobject,
  63. consisting of four integers:  width to left and right of the
  64. distinguished column mark, and height above and below the distinguished
  65. row mark.  These numbers are always non-negative in Basser Lout, but
  66. this restriction is unnecessary and should be dropped.
  67. @PP
  68. For the leaves, which are simple words, the numbers are obtained from
  69. font tables.  For the higher levels we apply recursive rules.  Suppose
  70. that @Eq { hgap(x, g, y) } returns the desired distance between the
  71. column marks of objects @Eq { x } and @Eq { y } when they are separated by
  72. gap @Eq { g }:  @Eq { right(x) + length(g) + left(y) } when the gap mode is
  73. edge-to-edge, the larger of @Eq { length(g) } and
  74. @Eq { right(x) + left(y) } when the mode is mark-to-mark, and so on.  Given
  75. an object
  76. @ID @Eq {
  77. X = x sub 1 ````` bar g sub 1 ````` ... ````` { "-2p" @Font "^"}bar g sub i-1
  78. ````` x sub i ````` ... ````` bar g sub n-1 ````` x sub n
  79. }
  80. we may calculate its size as follows:
  81. @ID @Eq {
  82. left(X) ^= left( x sub 1 ) + hgap( x sub 1 , g sub 1 , x sub 2 )
  83. + ... + hgap( x sub i-1 , g sub i-1 , x sub i )
  84. /1.4vx
  85. right(X) ^= hgap( x sub i , g sub i , x sub i+1 )
  86. + ... + hgap( x sub n-1 , g sub n-1 , x sub n ) + right( x sub n )
  87. /1.4vx
  88. "above"(X) ^= "above"(x sub 1 ) up ... up "above"(x sub n )
  89. /1.4vx
  90. "below"(X) ^= "below"(x sub 1 ) up ... up "below"(x sub n )
  91. }
  92. where @Eq { non up } returns the larger of its two parameters.  Similar
  93. formulas are easily derived for the other operators.
  94. @PP
  95. For purposes of exposition we will now make the simplifying
  96. assumptions that all gaps are {@Code "0i"}, all column marks lie at
  97. the left edge, and all row marks lie at the top edge.  Then the size
  98. of each object can be expressed by just two numbers, width and
  99. height, and the four formulas reduce to
  100. @ID @Eq {
  101. width( x sub 1 rel bar ... rel bar x sub n ) ^=
  102. width( x sub 1 ) + ... + width( x sub n )
  103. /1.4vx
  104. height( x sub 1 rel bar ... rel bar x sub n ) ^=
  105. height( x sub 1 ) up ... up height( x sub n )
  106. }
  107. The corresponding formulas for vertical concatenation are
  108. @ID @Eq {
  109. width( x sub 1 rel "/" ... rel "/" x sub n ) ^=
  110. width( x sub 1 ) up ... up width( x sub n )
  111. /1.4vx
  112. height( x sub 1 rel "/" ... rel "/" x sub n ) ^=
  113. height( x sub 1 ) + ... + height( x sub n )
  114. }
  115. According to these formulas, the height of
  116. @ID @Eq { @Fig { @Tree {
  117. @Node @FCircle fraction
  118. @LeftSub {
  119.    @Node @FCircle bar
  120.    @LeftSub  { @Node @FCircle a }
  121.    @RightSub { @Node @FCircle b }
  122. }
  123. @RightSub {
  124.    @Node @FCircle bar
  125.    @LeftSub  { @Node @FCircle c }
  126.    @RightSub { @Node @FCircle d }
  127. }
  128. }}}
  129. is
  130. @ID @Eq {
  131. [ height(a) up height(b)] + [ height(c) up height(d)]
  132. }
  133. which is correct, but for width they yield
  134. @ID @Eq {
  135. [ width(a) + width(b)] up [ width(c) + width(d)]
  136. }
  137. which is not, since it does not take the merging of column marks into
  138. account.  The asymmetry between horizontal and vertical has come
  139. about because the row entries, such as @Eq {a} and {@Eq {b}}, are
  140. adjacent in the tree, but the column entries, such as @Eq {a} and
  141. {@Eq {c}}, are not.  It would be possible to solve this cross-linking
  142. problem by augmenting the size information stored in each node to
  143. record the number of marks and the size of each, but the author has
  144. preferred the following method which makes structural changes to the
  145. tree instead.
  146. @PP
  147. If @Eq { a } and @Eq { c } share a column mark, they each might as well
  148. have width { @Eq {width(a) up width(c) }}, since all width calculations
  149. apply to entire columns.  Accordingly, we introduce a new operator,
  150. @Eq {COL}, defined by
  151. @ID @Eq { width( x sub 1 bin COL ... bin COL x sub n ) =
  152. width( x sub 1 ) up ... up width( x sub n )
  153. }
  154. and replace both @Eq { a } and @Eq { c } by {@Eq { a bin COL c }}.  To
  155. prevent @Eq { COL } operators from disturbing height calculations, we
  156. define a binary operator called @Eq { SPLIT } by
  157. @ID @Eq { width( x bin SPLIT y) ^= width(x)
  158. /1.4vx
  159. height( x bin SPLIT y) ^= height(y) }
  160. which switches height and width calculations onto different
  161. subtrees.  Then the transformation
  162. @ID @Eq {
  163. @Fig { @Tree {
  164.    @Node @FCircle a
  165. }}
  166. &2m ==> &2m
  167. @Fig { @Tree {
  168.    @Node @FEllipse SPLIT
  169.    @LeftSub {
  170.       @Node @FEllipse COL
  171.       @LeftSub  { @Node @FCircle a }
  172.       @RightSub { @Node @FCircle c }
  173.    }
  174.    @RightSub { @Node @FCircle a }
  175. }}
  176. }
  177. # where @Eq { S } denotes a @Eq { SPLIT } node and @Eq { C } denotes a
  178. # @Eq { COL } node,
  179. widens @Eq { a } to @Eq {width(a) up width(c) } without affecting its height;
  180. it is applied to every object that shares its column mark with at least
  181. one other object.  A similar transformation involving a @Eq { ROW } operator
  182. deals with shared row marks.  The effect on our little table is to replace
  183. @ID @Eq { @Fig { @Tree {
  184. @Node @FCircle fraction
  185. @LeftSub {
  186.    @Node @FCircle bar
  187.    @LeftSub  { @Node @FCircle a }
  188.    @RightSub { @Node @FCircle b }
  189. }
  190. @RightSub {
  191.    @Node @FCircle bar
  192.    @LeftSub  { @Node @FCircle c }
  193.    @RightSub { @Node @FCircle d }
  194. }
  195. }}}
  196. by
  197. @ID @Eq { @Fig maxlabels { "70" } { @Tree hmargin { "0.1c" } {
  198. @Node @FCircle fraction
  199. @FirstSub {
  200.    @Node @FCircle bar
  201.    @FirstSub  {
  202.       @Node @FEllipse SPLIT
  203.       @FirstSub {
  204.          @Node @FEllipse COL
  205.          @FirstSub  { @Node @FCircle a }
  206.          @NextSub { @Node @FCircle c }
  207.       }
  208.       @NextSub {
  209.          @Node @FEllipse ROW
  210.          @FirstSub  { @Node @FCircle a }
  211.          @NextSub { @Node @FCircle b }
  212.       }
  213.    }
  214.    @NextSub {
  215.       @Node @FEllipse SPLIT
  216.       @FirstSub {
  217.          @Node @FEllipse COL
  218.          @FirstSub  { @Node @FCircle b }
  219.          @NextSub { @Node @FCircle d }
  220.       }
  221.       @NextSub {
  222.          @Node @FEllipse ROW
  223.          @FirstSub  { @Node @FCircle a }
  224.          @NextSub { @Node @FCircle b }
  225.       }
  226.    }
  227. }
  228. @NextSub {
  229.    @Node @FCircle bar
  230.    @FirstSub  {
  231.       @Node @FEllipse SPLIT
  232.       @FirstSub {
  233.          @Node @FEllipse COL
  234.          @FirstSub  { @Node @FCircle a }
  235.          @NextSub { @Node @FCircle c }
  236.       }
  237.       @NextSub {
  238.          @Node @FEllipse ROW
  239.          @FirstSub  { @Node @FCircle c }
  240.          @NextSub { @Node @FCircle d }
  241.       }
  242.    }
  243.    @NextSub {
  244.       @Node @FEllipse SPLIT
  245.       @FirstSub {
  246.          @Node @FEllipse COL
  247.          @FirstSub  { @Node @FCircle b }
  248.          @NextSub { @Node @FCircle d }
  249.       }
  250.       @NextSub {
  251.          @Node @FEllipse ROW
  252.          @FirstSub  { @Node @FCircle c }
  253.          @NextSub { @Node @FCircle d }
  254.       }
  255.    }
  256. }
  257. }}}
  258. In fact, common subexpressions are identified (trivially) and the result
  259. is a directed acyclic graph; each affected leaf has two parents, one for
  260. width and one for height; and each @Eq { COL } or @Eq { ROW } node has
  261. one parent and one child for each object lying on the corresponding
  262. mark.  The data structure roughly doubles in size, and this occurs only
  263. rarely in practice.
  264. @PP
  265. This method can cope with any legal input, including
  266. @ID @Code {
  267. "{  a  //  c  |  d  }  |  {  b  /  e  }"
  268. "/  {  f  /  i  }  |  {  g  |  h  //  j  }"
  269. }
  270. which produces overlapping spanning columns:
  271. @ID @I @Fig {
  272.     @FBox margin { 0.2c } width { 1.6c } 1.2f @Font a |
  273.     @FBox margin { 0.2c } width { 0.6c } 1.2f @Font b |
  274. //  @FBox margin { 0.2c } width { 0.6c } 1.2f @Font c |
  275.     @FBox margin { 0.2c } width { 0.6c } 1.2f @Font d |
  276.     @FBox margin { 0.2c } width { 0.6c } 1.2f @Font e |
  277. //  @FBox margin { 0.2c } width { 0.6c } 1.2f @Font f |
  278.     @FBox margin { 0.2c } width { 0.6c } 1.2f @Font g |
  279.     @FBox margin { 0.2c } width { 0.6c } 1.2f @Font h |
  280. //  @FBox margin { 0.2c } width { 0.6c } 1.2f @Font i |
  281.     @FBox margin { 0.2c } width { 1.6c } 1.2f @Font j |
  282. }
  283. The boxes have been added to clarify the structure.  The width of this
  284. object is formally
  285. @ID @Eq { ((width(a) up (x + y)) + z) up (x + ((y + z) up width(j))) }
  286. where
  287. @IL
  288. @ListItem @Eq { x = width(c) up width(`f`) up width(i) }
  289. @ListItem @Eq { y = width(d`) up width(g) }
  290. @ListItem @Eq { z = width(b) up width(e) up width(h) }
  291. @EL
  292. It seems clear that @Eq { y } at least must appear twice in any
  293. expression for the width of this object made out of simple addition
  294. and maxing operations, showing that an ordinary tree
  295. structure is insufficient for overlapping spanning columns.  The Basser
  296. Lout interpreter actually rejects such structures, owing to the author's
  297. doubts about the implementability of @I Constrained and @I AdjustSize
  298. (Section {@NumberOf constraints}) on them; but with hindsight this caution
  299. was unnecessary.
  300. @PP
  301. The directed acyclic graph is ordered in the sense that the order of
  302. the edges entering and leaving each node matters.  The structure is
  303. highly dynamic, and traversals both with and against the arrows are
  304. required.  After a few ad-hoc attempts to extend the usual tree
  305. representation had failed, the author developed a representation based
  306. on doubly linked lists of records denoting links, whose flexibility more
  307. than compensated for the somewhat excessive memory consumption.  For example,
  308. @ID @Eq { @Fig {
  309.        A:: @FCircle a   |2c                  |2c  B:: @FCircle b
  310. /1.5c  C:: @FCircle c   |    D:: @FCircle d
  311. // A @JoinFigures arrow { forward } C
  312. // A @JoinFigures arrow { forward } D
  313. // B @JoinFigures arrow { forward } D
  314. }}
  315. is represented by
  316. @CD @Eq { @Fig maxlabels { "300" } {
  317. A:: @DagBox mid { @BlackDot } base { a } |2c |2c |2c |2c
  318. B:: @DagBox mid { @BlackDot } base { b }
  319. /1c L:: @DagBox top { @BlackDot } mid { @BlackDot } base { LK }
  320. |   M:: @DagBox top { @BlackDot } mid { @BlackDot } base { LK }
  321. | | N:: @DagBox top { @BlackDot } mid { @BlackDot } base { LK }
  322. /1c
  323. C:: @DagBox top { @BlackDot } base { c } | |
  324. D:: @DagBox top { @BlackDot } base { d }
  325. // @TVShape nw { A@MID@CTR } ne { A@MID@CTR } sw {L@MID@CTR } se { M@MID@CTR }
  326. // @TVShape nw { L@TOP@CTR } ne { L@TOP@CTR } sw {C@TOP@CTR } se { C@TOP@CTR }
  327. // @TVShape nw { M@TOP@CTR } ne { N@TOP@CTR } sw {D@TOP@CTR } se { D@TOP@CTR }
  328. // @TVShape nw { B@MID@CTR } ne { B@MID@CTR } sw {N@MID@CTR } se { N@MID@CTR }
  329. }}
  330. where @Eq { LK } tags a record representing a link.  The first list
  331. in any node contains all the incoming links, the second contains the
  332. outgoing ones.  The node serves as the header for both lists.  The
  333. required operations reduce to simple appends, deletes, and traversals
  334. of doubly linked lists, all having small constant cost.  There is a
  335. highly tuned memory allocator, and care is taken to dispose of each node
  336. when the last incoming link is deleted, so that there is no need for
  337. garbage collection.
  338. @PP
  339. In normal use the number of nodes at higher levels of the dag is small
  340. in comparison with the leaves and their incoming links, so we may
  341. estimate the space complexity at about 60 bytes per input word (20 bytes
  342. per link, 40 per leaf node).  Careful optimization could easily halve
  343. this, but since memory is reclaimed after printing each page there is
  344. little need.
  345. @End @SubSection
  346.