193 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			193 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
def
 | 
						|
  bits.in.character	= 8,
 | 
						|
  number.of.characters= 1 << bits.in.character,
 | 
						|
  number.of.codes	= number.of.characters + 1,
 | 
						|
  character.mask	= not ((not 0) << bits.in.character):
 | 
						|
 | 
						|
def
 | 
						|
  root = 0, size.of.tree = (2* number.of.codes)-1, not.a.node = size.of.tree:
 | 
						|
 | 
						|
var
 | 
						|
  escape, weight[size.of.tree],
 | 
						|
  children[size.of.tree], parent[size.of.tree],
 | 
						|
  character[size.of.tree], representative[number.of.characters] :
 | 
						|
 | 
						|
proc construct.tree =
 | 
						|
  -- Create a tree for the encoding in which every character is escaped
 | 
						|
  seq
 | 
						|
    escape := root
 | 
						|
    weight[escape] := 1
 | 
						|
    children[escape] := root		-- it is a leaf
 | 
						|
    seq ch= [0 for number.of.characters]
 | 
						|
      representative[ch] := not.a.node					:
 | 
						|
 | 
						|
proc create.leaf(var new.leaf, value ch) =
 | 
						|
  -- Extend the tree by fision of the escape leaf into two new leaves
 | 
						|
  var new.escape:
 | 
						|
  seq
 | 
						|
    new.leaf		:= escape + 1
 | 
						|
    new.escape		:= escape + 2
 | 
						|
 | 
						|
    children[escape]	:= new.leaf	-- escape is the new parent
 | 
						|
 | 
						|
    weight[new.leaf]	:= 0
 | 
						|
    children[new.leaf]	:= root
 | 
						|
    parent[new.leaf]	:= escape
 | 
						|
    character[new.leaf]	:= ch
 | 
						|
    representative[ch /\ character.mask] := new.leaf
 | 
						|
 | 
						|
    weight[new.escape]	:= 1
 | 
						|
    children[new.escape]:= root
 | 
						|
    parent[new.escape]	:= escape
 | 
						|
 | 
						|
    escape		:= new.escape					:
 | 
						|
 | 
						|
proc swap.trees(value i, j) =
 | 
						|
  -- Exchange disjoint sub-trees routed at i and j
 | 
						|
  proc swap.words(var p,q) =
 | 
						|
    -- Exchange values stored in p and q
 | 
						|
    var t:
 | 
						|
    seq
 | 
						|
      t := p
 | 
						|
      p := q
 | 
						|
      q := t								:
 | 
						|
 | 
						|
  proc adjust.offspring(value i) =
 | 
						|
    -- Restore downstream pointers to node i
 | 
						|
    if
 | 
						|
      children[i] = root
 | 
						|
	representative[character[i] /\ character.mask] := i
 | 
						|
      children[i] <> root
 | 
						|
	seq child=[children[i] for 2]
 | 
						|
	  parent[child] := i						:
 | 
						|
  
 | 
						|
  seq
 | 
						|
    swap.words(children[i], children[j])
 | 
						|
    swap.words(character[i], character[j])
 | 
						|
    adjust.offspring(i)
 | 
						|
    adjust.offspring(j)							:
 | 
						|
 | 
						|
proc increment.frequency(value ch) =
 | 
						|
  -- Adjust the weights of all relevant nodes to account for one more occurence
 | 
						|
  -- of the character ch, and adjust the shape of the tree if necessary
 | 
						|
  var node:
 | 
						|
  seq
 | 
						|
    if
 | 
						|
      representative[ch /\ character.mask] <> not.a.node
 | 
						|
	node := representative[ch /\ character.mask]
 | 
						|
      representative[ch /\ character.mask] = not.a.node
 | 
						|
        create.leaf(node, ch)
 | 
						|
    while node <> root
 | 
						|
      if
 | 
						|
	weight[node-1] > weight[node]
 | 
						|
	  seq
 | 
						|
	    weight[node] := weight[node] + 1
 | 
						|
	    node := parent[node]
 | 
						|
	weight[node-1] = weight[node]
 | 
						|
	  if i= [1 for (node-root)-1]
 | 
						|
	    weight[(node-i)-1] > weight[node]
 | 
						|
	      seq
 | 
						|
		swap.trees(node, node-i)
 | 
						|
		node := node-i
 | 
						|
    weight[root] := weight[root] + 1					:
 | 
						|
 | 
						|
proc encode.character(chan output, value ch) =
 | 
						|
  -- Transmit the encoding of ch along output
 | 
						|
  def size.of.encoding = bits.in.character + (number.of.codes - 1) :
 | 
						|
  var encoding[size.of.encoding], length, node:
 | 
						|
  seq
 | 
						|
    if
 | 
						|
      representative[ch /\ character.mask] <> not.a.node
 | 
						|
	seq
 | 
						|
	  length := 0
 | 
						|
	  node := representative[ch /\ character.mask]
 | 
						|
      representative[ch /\ character.mask] = not.a.node
 | 
						|
	seq
 | 
						|
	  seq i=[0 for bits.in.character]
 | 
						|
	    encoding[i] := (ch >> i) /\ 1	-- i'th bit of unencoded ch
 | 
						|
	  length := bits.in.character
 | 
						|
	  node := escape
 | 
						|
    while node <> root
 | 
						|
      seq
 | 
						|
	encoding[length] := node - children[parent[node]]
 | 
						|
	length := length + 1
 | 
						|
	node := parent[node]
 | 
						|
    seq i= [1 for length]
 | 
						|
      output ! encoding[length-i]					:
 | 
						|
 | 
						|
proc decode.character(chan input, var ch) =
 | 
						|
  -- Receive an encoding along input and store the corresponding character in ch
 | 
						|
  var node:
 | 
						|
  seq
 | 
						|
    node := root
 | 
						|
    while children[node] <> root
 | 
						|
      var bit:
 | 
						|
      seq
 | 
						|
	input ? bit
 | 
						|
	node := children[node] + bit
 | 
						|
    if
 | 
						|
      node < escape
 | 
						|
	ch := character[node]
 | 
						|
      node = escape
 | 
						|
	var bit:
 | 
						|
	seq
 | 
						|
	  input ? bit
 | 
						|
	  ch := -bit
 | 
						|
	  seq i= [2 for bits.in.character - 1]
 | 
						|
	    seq
 | 
						|
	      input ? bit
 | 
						|
	      ch := (ch << 1) \/ bit					:
 | 
						|
 | 
						|
def end.of.message = -1:
 | 
						|
 | 
						|
proc copy.encoding(chan source, sink) =
 | 
						|
  -- Read a stream of characters from source, until signalled on end.of.source,
 | 
						|
  -- and transmit their encodings in sequence along sink, followed by that of
 | 
						|
  -- end.of.message, maintaining throughout the encoding tree for the encoding
 | 
						|
  -- determined by the cumulative frequencies of the characters transmitted
 | 
						|
  var more.characters.expected:
 | 
						|
  seq
 | 
						|
    construct.tree
 | 
						|
    more.characters.expected := true
 | 
						|
    while more.characters.expected
 | 
						|
      var ch:
 | 
						|
      seq
 | 
						|
	source ? ch
 | 
						|
	if
 | 
						|
	  ch <> end.of.message
 | 
						|
	    seq
 | 
						|
	      encode.character(sink, ch)
 | 
						|
	      increment.frequency(ch)
 | 
						|
	  ch = end.of.message
 | 
						|
	    more.characters.expected := false
 | 
						|
    encode.character(sink, end.of.message)				:
 | 
						|
 | 
						|
proc copy.decoding(chan source, sink) =
 | 
						|
  -- Read the encodings of a stream of characters, up to and including the
 | 
						|
  -- encoding of end.of.message, from source and transmit the corresponding
 | 
						|
  -- characters along sink, maintaining the encoding tree for encoding
 | 
						|
  -- determined by the cumulative frequencies of the characters received
 | 
						|
  var more.characters.expected:
 | 
						|
  seq
 | 
						|
    construct.tree
 | 
						|
    more.characters.expected := true
 | 
						|
    while more.characters.expected
 | 
						|
      var ch:
 | 
						|
      seq
 | 
						|
	decode.character(source, ch)
 | 
						|
	if
 | 
						|
	  ch <> end.of.message
 | 
						|
	    seq
 | 
						|
	      sink ! ch
 | 
						|
	      increment.frequency(ch)
 | 
						|
	  ch = end.of.message
 | 
						|
	    more.characters.expected:=false				:
 | 
						|
 | 
						|
var choose:
 | 
						|
seq
 | 
						|
  input ? choose
 | 
						|
  if
 | 
						|
    choose='e'
 | 
						|
      copy.encoding(input, output)
 | 
						|
    choose='d'
 | 
						|
      copy.decoding(input, output)
 |