***************************
*  Dictionary Operations  *
***************************

dictbeg equ 0
dictpos equ 4
dictlim equ 8
dictalt equ 12

**************************************************
*  Define name (D0=size,A0=name,A1=dict/D0=tag)  *
*  D0<0: Name already defined  D0=0: dict full   *
**************************************************

defname addq.l #3,d0 * Round up to an integral
  lsr.l #2,d0        * number of longwords
  movem.l d0-d2/a0-a3,-(sp)
  clr.l d0
  move.b (a0)+,d0    * Length of string
  move.l dictbeg(a1),a2
  cmp.l dictpos(a1),a2
  bne.s dn1          * Dictionary not empty ->
  clr.l (a2)+        * Initialise dictionary
  clr.l (a2)+
  move.l a2,dictpos(a1)
  subq.l #8,a2
dn1 clr.b d1
  subq.l #1,d0       * Advance along string
  bmi.s dn2          * End of string: match 0
  move.b (a0)+,d1    * Otherwise match next char
dn2 move.l a2,a3     * A3 -> predecessor
  addq.l #4,a2       * A2 -> next candidate
dn3 cmp.b (a2),d1
  bne.s dn4          * Mismatch ->
  tst.b d1
  bne dn1            * Not yet done ->
  move.l #$80000004,d0 * (Duplicate)
  add.l a2,d0
  addq.l #4,sp
  movem.l (sp)+,d1/d2/a0-a3
  rts
dn4 clr.l d2
  move.w 2(a2),d2  * get alt pointer
  beq.s dn5          * no alt ->
  lsl.l #2,d2        * scale-up
  add.l d2,a2
  bra dn3            * Try alt
dn5 move.l a3,d2     * Remember predecessor
  move.l dictpos(a1),a3
  move.l d0,-(sp)    * Preserve (rest of) string length
  addq.l #3,d0       * Test for dict overflow
  add.l 4(sp),d0
  lsl.l #2,d0
  add.l a3,d0
  cmp.l dictlim(a1),d0
  bge.s dn9          * Dict full ->
  move.l d0,dictpos(a1) * Allocate space
  move.l (sp)+,d0
  sub.l a3,d2
  clr.w (a3)+
  neg.l d2
  lsr.l #2,d2        * scale-down (back-pointer)
  move.w d2,(a3)+
  move.l a3,d2
  sub.l a2,d2
  lsr.l #2,d2        * scale-down (alt-pointer)
  move.w d2,2(a2)
dn6 move.b d1,(a3)+
  clr.b (a3)+
  clr.w (a3)+
  tst.w d0
  bmi.s dn7          * done ->
  clr.w d1           * Extract next char (or 0)
  subq.w #1,d0
  bmi dn6
  move.b (a0)+,d1
  bra dn6
dn7 move.l a3,d0
  addq.l #4,sp
  movem.l (sp)+,d1/d2/a0-a3
  rts
dn9 sub.l a3,a3      * Dictionary full
  addq.l #4,sp       *30/05/85 bugfix
  bra dn7

*********************************************
*  Reference name (A0=name,A1=dict/D0=tag)  *
*  D0=0: not found,  D0<0: approx match     *
*********************************************

refname movem.l d1/d2/a0-a2,-(sp)
rn0 clr.l d0
  move.b (a0)+,d0  * Length of string
  move.l dictbeg(a1),a2
rn1 clr.b d1       * Advance along string
  subq.l #1,d0
  bmi.s rn2        * D1=0 for end of string ->
  move.b (a0)+,d1
rn2 addq.l #4,a2   * Advance along dict
rn3 cmp.l dictpos(a1),a2
  bge.s rn5        * Off end ->
  cmp.b (a2),d1
  bne.s rn4        * Mismatch here ->
  tst.b d1
  beq.s rn9        * Complete match ->
  bra rn1
rn4 clr.l d2
  move.w 2(a2),d2
  beq.s rn5        * No alt ->
  lsl.l #2,d2      * scale-up
  add.l d2,a2
  bra rn3          * Try elsewhere
rn5 tst.b d1
  beq rn8          * Approx match ->
  move.l 8(sp),a0  * Reset string pointer
  move.l dictalt(a1),d0 * Try alt dict if any
  move.l d0,a1
  bne rn0
  clr.l d0         * Name not found =>
  bra.s rn10
rn8 addq.l #4,a2   * scan to end of this name
  tst.b (a2)
  bne rn8
  add.l #$80000000,a2 * (A2 preserved across recursive call)
  move.l 8(sp),a0  * Try alt dict for better match
  move.l dictalt(a1),d0
  move.l d0,a1
  beq.s rn9         * No alt dict ->
  bsr refname
  tst.l d0
  bgt.s rn10        * Better match found ->
rn9 addq.l #4,a2
  move.l a2,d0
rn10 movem.l (sp)+,d1/d2/a0-a2
  rts

*************************************
*  Translate name (D0=tag,A0=name)  *
*************************************

transname movem.l d0-d2/a0-a2,-(sp)
  clr.b (a0)        * string = ""
  lea 1(a0),a1      * Pointer along string
  move.l d0,a2      * Dict tag
  subq.l #8,a2      * Pointer along dict
tn1 move.b (a2),d0  * Character
  bne.s tn2         * Genuine ->
  clr.l d0
  move.w 2(a2),d0   * Get predecessor
  beq.s tn3         * None ->
  lsl.l #2,d0       * scale-up
  sub.l d0,a2
  bra tn1
tn2 move.b d0,(a1)+
  subq.l #4,a2      * Get predecessor
  bra tn1
tn3 move.l a1,d0
  sub.l a0,d0
  subq.b #1,d0
  move.b d0,(a0)    * Set string length
  lea 1(a0),a2
tn4 subq.b #2,d0    * Reverse the string
  bmi.s tn5         * Done ->
  move.b (a2),d1
  move.b -(a1),d2
  move.b d1,(a1)
  move.b d2,(a2)+
  bra tn4
tn5 movem.l (sp)+,d0-d2/a0-a2
  rts

  end
