1 #target WASI // So that we can target Firefox 52.
   2 
   3 Function noMoreFreeMemory() Which Returns Nothing Is External;
   4 Function segmentationFault() Which Returns Nothing Is External;
   5 Function
   6 printString(PointerToCharacter string) Which Returns Nothing Is External;
   7 Function clearScreen() Which Returns Nothing Is External;
   8 Function getLengthOfTheInput() Which Returns Integer16 Is External;
   9 Function
  10 getCharacterOfTheInput(Integer16 index) Which Returns Character Is External;
  11 Function setDiagramWidth(Integer32 width) Which Returns Nothing Is External;
  12 Function setDiagramHeight(Integer32 height) Which Returns Nothing Is External;
  13 Function drawLine(Integer32 x1, Integer32 y1, Integer32 x2,
  14                   Integer32 y2) Which Returns Nothing Is External;
  15 Function drawRectangle(Integer32 x, Integer32 y, Integer32 width,
  16                        Integer32 height) Which Returns Nothing Is External;
  17 Function drawText(Integer32 x, Integer32 y,
  18                   PointerToCharacter text) Which Returns Nothing Is External;
  19 
  20 Integer32 NDEBUG := 1,
  21                  MAINTAIN_COMPATIBILITY_WITH_JAVASCRIPT_IMPLEMENTATION := 1;
  22 // The JavaScript implementation is available here:
  23 // https://flatassembler.github.io/huffman.html
  24 
  25 Structure TreeNode Consists Of
  26   Character character;
  27   Integer16 frequencyOfCharacter;
  28   PointerToTreeNode leftChild, rightChild;
  29   Character code[16];
  30   Integer32 x, y;
  31 EndStructure
  32 
  33 InstantiateStructure TreeNode treeNodes[64];
  34 Integer16 isTreeNodeUsed[64];
  35 
  36 Function isTreeNodeWithinBounds(
  37     PointerToTreeNode treeNode) Which Returns Integer32 Does
  38   Return AddressOf(treeNodes[0]) <= treeNode <= AddressOf(treeNodes[64 - 1]) and
  39       mod(treeNode - AddressOf(treeNodes[0]), SizeOf(TreeNode)) =
  40       0; // In C, testing whether the mod is equal to 0 would not be necessary,
  41          // but, since AEC supports unaligned access, it is necessary here.
  42 EndFunction
  43 
  44 Function
  45 convertIntegerToString(PointerToCharacter string,
  46                        Integer32 integer) Which Returns Nothing Is Declared;
  47 Function appendIntegerToString(PointerToCharacter string, Integer32 integer)
  48                        Which Returns Nothing Is Declared;
  49 Function strcat(PointerToCharacter dest,
  50                 PointerToCharacter src) Which Returns Nothing Is Declared;
  51 Function strlen(PointerToCharacter string) Which Returns Integer32 Is Declared;
  52 
  53 Function newTreeNode() Which Returns PointerToTreeNode Does
  54   Integer16 i := 0;
  55   While i < 64 Loop 
  56     If not(isTreeNodeUsed[i]) Then
  57       treeNodes[i].character := 0;
  58       treeNodes[i].leftChild := treeNodes[i].rightChild
  59           := PointerToTreeNode(0);
  60       treeNodes[i].code[0] := 0;
  61       treeNodes[i].frequencyOfCharacter := 0;
  62       isTreeNodeUsed[i] := 1;
  63       If NDEBUG = 0 Then
  64         Character stringToBePrinted[64] := {0};
  65         strcat(AddressOf(stringToBePrinted[0]),
  66                "NDEBUG: Allocating the TreeNode #");
  67         appendIntegerToString(AddressOf(stringToBePrinted[0]),
  68                                i);
  69         strcat(AddressOf(stringToBePrinted[0]), "\n");
  70         printString(AddressOf(stringToBePrinted[0]));
  71       EndIf
  72       Return AddressOf(treeNodes[i]);
  73     EndIf
  74     i += 1;
  75   EndWhile
  76   noMoreFreeMemory();
  77 EndFunction
  78 
  79 Function freeTreeNode(PointerToTreeNode treeNode) Which Returns Nothing Does
  80   If not(isTreeNodeWithinBounds(treeNode)) Then
  81     segmentationFault();
  82   EndIf
  83   If NDEBUG = 0 Then
  84     Character stringToBePrinted[64] := {0};
  85     strcat(AddressOf(stringToBePrinted[0]), "NDEBUG: Freeing the TreeNode #");
  86     appendIntegerToString(AddressOf(stringToBePrinted[0]),
  87                            (treeNode - AddressOf(treeNodes[0])) /
  88                                SizeOf(TreeNode));
  89     strcat(AddressOf(stringToBePrinted[0]), "\n");
  90     printString(AddressOf(stringToBePrinted[0]));
  91   EndIf
  92   isTreeNodeUsed[(treeNode - AddressOf(treeNodes[0])) / SizeOf(TreeNode)] := 0;
  93 EndFunction
  94 
  95 Function getHeight(PointerToTreeNode node) Which Returns Integer32 Does 
  96   If not(node) Then 
  97     Return 0; 
  98   EndIf
  99   Integer32 max := 0;
 100   If getHeight(node->leftChild) > max Then
 101     max := getHeight(node->leftChild);
 102   EndIf
 103   If getHeight(node->rightChild) > max Then
 104     max := getHeight(node->rightChild);
 105   EndIf
 106   Return max + 1;
 107 EndFunction
 108 
 109 Function strlen(PointerToCharacter str) Which Returns Integer32 Does
 110   If str = 0 Then
 111     Return 0;
 112   EndIf
 113   Integer32 length := 0;
 114   While ValueAt(str + length) Loop
 115     length += 1;
 116   EndWhile
 117   Return length;
 118 EndFunction
 119 
 120 Function strncmp(PointerToCharacter first, PointerToCharacter second,
 121                  Integer32 n) Which Returns Integer32 Does
 122   If first = 0 or second = 0 Then
 123     Return 1;
 124   EndIf
 125   Integer32 iterator := 0;
 126   While iterator < n Loop
 127     If ValueAt(first + iterator) = ValueAt(second + iterator) Then
 128       iterator += 1;
 129     Else 
 130       Return ValueAt(first + iterator) - ValueAt(second + iterator);
 131     EndIf
 132   EndWhile
 133   Return 0;
 134 EndFunction
 135 
 136 Function strcpy(PointerToCharacter dest,
 137                 PointerToCharacter src) Which Returns Nothing Does
 138   While ValueAt(src) Loop
 139     ValueAt(dest) := ValueAt(src);
 140     dest += 1;
 141     src += 1;
 142   EndWhile
 143   ValueAt(dest) := 0;
 144 EndFunction
 145 
 146 Function strcat(PointerToCharacter dest,
 147                 PointerToCharacter src) Which Returns Nothing Does
 148   strcpy(dest + strlen(dest), src);
 149 EndFunction
 150 
 151 Function reverseString(PointerToCharacter string) Which Returns Nothing Does
 152   PointerToCharacter pointerToLastCharacter := string + strlen(string) - 1;
 153   While pointerToLastCharacter - string > 0 Loop
 154     Character tmp := ValueAt(string);
 155     ValueAt(string) := ValueAt(pointerToLastCharacter);
 156     ValueAt(pointerToLastCharacter) := tmp;
 157     string += 1;
 158     pointerToLastCharacter -= 1;
 159   EndWhile
 160 EndFunction
 161 
 162 Function convertIntegerToString(PointerToCharacter string,
 163                                 Integer32 number) Which Returns Nothing Does
 164   Integer32 isNumberNegative := 0;
 165   If number < 0 Then
 166     number *= -1;
 167     isNumberNegative := 1;
 168   EndIf
 169   Integer32 i := 0;
 170   While number >= 10 Loop
 171     ValueAt(string + i) := '0' + mod(number, 10);
 172     number /= 10;
 173     i += 1;
 174   EndWhile
 175   ValueAt(string + i) := '0' + number;
 176   i += 1;
 177   If isNumberNegative Then
 178     ValueAt(string + i) := '-';
 179     i += 1;
 180   EndIf
 181   ValueAt(string + i) := 0;
 182   reverseString(string);
 183 EndFunction
 184 
 185 Function appendIntegerToString(PointerToCharacter string,
 186                                Integer32 number) Which Returns Nothing Does
 187   convertIntegerToString(string + strlen(string), number);
 188 EndFunction
 189 
 190 Function convertDecimalToString(PointerToCharacter string,
 191                                 Decimal32 number) Which Returns Nothing Does 
 192   convertIntegerToString(string, number);
 193   number -= Integer32(number);
 194   If number < 0 Then
 195     number *= -1; 
 196   EndIf
 197   If number = 0 Then 
 198     Return;
 199   EndIf
 200   strcat(string, ".");
 201   Integer16 numberOfDecimals := 0;
 202   While numberOfDecimals < 3 and number > 0 Loop
 203     numberOfDecimals += 1;
 204     number *= 10;
 205     Character stringWithTheNewDigit[2];
 206     stringWithTheNewDigit[0] := stringWithTheNewDigit[1] := 0;
 207     stringWithTheNewDigit[0] := '0' + number;
 208     strcat(string, AddressOf(stringWithTheNewDigit[0]));
 209     number -= Integer32(number);
 210   EndWhile
 211 EndFunction
 212 
 213 PointerToCharacter mapOfCodes[256];
 214 
 215 Function assignCode(PointerToCharacter currentCode,
 216                     PointerToTreeNode treeNode) Which Returns Nothing Does
 217   If NDEBUG = 0 Then
 218     Character stringToBePrinted[64] := {0};
 219     strcat(AddressOf(stringToBePrinted[0]), "NDEBUG: Assigning the code \"");
 220     strcat(AddressOf(stringToBePrinted[0]), currentCode);
 221     strcat(AddressOf(stringToBePrinted[0]), "\" to the TreeNode #");
 222     appendIntegerToString(AddressOf(stringToBePrinted[0]),
 223                            (treeNode - AddressOf(treeNodes[0])) /
 224                                SizeOf(TreeNode));
 225     strcat(AddressOf(stringToBePrinted[0]), ".\n");
 226     printString(AddressOf(stringToBePrinted[0]));
 227 
 228     stringToBePrinted[0] := 0;
 229     strcat(AddressOf(stringToBePrinted[0]),
 230            "NDEBUG: Its left child is the TreeNode #");
 231     If treeNode->leftChild Then
 232       appendIntegerToString(AddressOf(stringToBePrinted[0]),
 233                              (treeNode->leftChild - AddressOf(treeNodes[0])) /
 234                                  SizeOf(TreeNode));
 235     Else
 236       strcat(AddressOf(stringToBePrinted[0]), "null");
 237     EndIf
 238     strcat(AddressOf(stringToBePrinted[0]), ".\n");
 239     printString(AddressOf(stringToBePrinted[0]));
 240 
 241     stringToBePrinted[0] := 0;
 242     strcat(AddressOf(stringToBePrinted[0]),
 243            "NDEBUG: Its right child is the TreeNode #");
 244     If treeNode->leftChild Then
 245       appendIntegerToString(AddressOf(stringToBePrinted[0]),
 246                              (treeNode->rightChild - AddressOf(treeNodes[0])) /
 247                                  SizeOf(TreeNode));
 248     Else
 249       strcat(AddressOf(stringToBePrinted[0]), "null");
 250     EndIf
 251     strcat(AddressOf(stringToBePrinted[0]), ".\n");
 252     printString(AddressOf(stringToBePrinted[0]));
 253   EndIf
 254 
 255   If not(isTreeNodeWithinBounds(treeNode)) Then segmentationFault(); EndIf
 256 
 257   strcpy(AddressOf(treeNode->code[0]), currentCode);
 258 
 259   Character leftCode[16] := {0}, rightCode[16] := {0};
 260 
 261   strcpy(AddressOf(leftCode[0]), currentCode);
 262   strcat(AddressOf(leftCode[0]), "0");
 263   strcpy(AddressOf(rightCode[0]), currentCode);
 264   strcat(AddressOf(rightCode[0]), "1");
 265 
 266   If treeNode->leftChild Then
 267     assignCode(AddressOf(leftCode[0]), treeNode->leftChild);
 268   EndIf
 269   If treeNode->rightChild Then
 270     assignCode(AddressOf(rightCode[0]), treeNode->rightChild);
 271   EndIf
 272 
 273   If treeNode->character Then
 274     mapOfCodes[treeNode->character] := AddressOf(treeNode->code[0]);
 275     Character codeToPrint[32] := {
 276       '\'',
 277       treeNode->character,
 278       '\'',
 279       '=',
 280       '>',
 281       0,
 282     };
 283     strcat(AddressOf(codeToPrint[0]), AddressOf(treeNode->code[0]));
 284     strcat(AddressOf(codeToPrint[0]), "\n");
 285     printString(AddressOf(codeToPrint[0]));
 286   EndIf
 287 EndFunction
 288 
 289 Function freeUpTheTree(PointerToTreeNode tree) Which Returns Nothing Does
 290   If tree->leftChild Then
 291     freeUpTheTree(tree->leftChild); // Calling `freeTreeNode` here instead of
 292                                     // `freeUpTheTree` causes a memory leak.
 293   EndIf
 294   If tree->rightChild Then
 295     freeUpTheTree(tree->rightChild);
 296   EndIf
 297   freeTreeNode(tree);
 298 EndFunction
 299 
 300 Decimal32 PRECISION := 500;
 301 Function ln(Decimal32 x) Which Returns Decimal32 Does
 302   // Natural logarithm is the integral of 1/x from 1 to x, highschool math.
 303   Decimal32 sum := 0, epsilon := (x - 1) / (5 * PRECISION), i := 1;
 304   While epsilon > 0 and i < x or epsilon < 0 and i > x Loop
 305     sum += epsilon / i;
 306     i += epsilon;
 307   EndWhile
 308   Return sum;
 309 EndFunction
 310 
 311 Decimal32 ln2 := log(2); // A compile-time constant.
 312 
 313 Function log2(Decimal32 x) Which Returns Decimal32 Does
 314   Return ln(x) / ln2;
 315 EndFunction
 316 
 317 Character input[64];
 318 Character output[256];
 319 
 320 Function getAddressOfTheOutput() Which Returns PointerToCharacter
 321     Does   // To be invoked by the `automaticTest.js` file in the
 322            // `HuffmanCodingInAEC` folder (that file is supposed to be run in
 323            // NodeJS) when the `main` function finishes executing, to compare
 324            // the Huffman coding stored in `output` with the known good
 325            // encodings for test strings.
 326   Return AddressOf(output[0]);
 327 EndFunction;
 328 
 329 Function shl(Integer32 first_number,
 330              Integer32 second_number) Which Returns Integer32 Does
 331   Return asm_i32(R"WebAssembly(
 332 (i32.shl
 333 	(i32.load %first_number)
 334 	(i32.load %second_number)
 335 )
 336 )WebAssembly");
 337 EndFunction
 338 
 339 Structure Maxima Consists Of
 340   Integer32 minimumX, maximumX;
 341 EndStructure
 342 Integer32 minimumX, maximumX;
 343 
 344 Function
 345 findMinimumAndMaximumX(PointerToTreeNode node,
 346                        PointerToMaxima maxima) Which Returns Nothing Does
 347   If node->x < maxima->minimumX Then
 348     maxima->minimumX := node->x;
 349   EndIf
 350   If node->x > maxima->maximumX Then
 351     maxima->maximumX := node->x;
 352   EndIf
 353 
 354   If node->rightChild Then
 355     findMinimumAndMaximumX(node->rightChild, maxima);
 356   EndIf
 357   If node->leftChild Then 
 358     findMinimumAndMaximumX(node->leftChild, maxima);
 359   EndIf
 360 EndFunction
 361 
 362 Function setCoordinates(PointerToTreeNode node, Integer32 x, Integer32 y,
 363                         Integer32 space) Which Returns Nothing Does
 364   node->x := x;
 365   node->y := y;
 366   If node->leftChild Then
 367     Integer32 newX := x - space - 10;
 368     While 1 Loop
 369       newX += 10;
 370       setCoordinates(node->leftChild, newX, y + 75,
 371                      20 * shl(1, getHeight(node->leftChild) - 1));
 372       InstantiateStructure Maxima localMaxima;
 373       localMaxima.maximumX := localMaxima.minimumX := newX;
 374       findMinimumAndMaximumX(node->leftChild, AddressOf(localMaxima));
 375       If x - localMaxima.maximumX <= 60 Then 
 376         Break;
 377       EndIf
 378     EndWhile
 379   EndIf
 380   If node->rightChild Then
 381     Integer32 newX := x + space + 10;
 382     While 1 Loop
 383       newX -= 10;
 384       setCoordinates(node->rightChild, newX, y + 75,
 385                      20 * shl(1, getHeight(node->rightChild) - 1));
 386       InstantiateStructure Maxima localMaxima;
 387       localMaxima.maximumX := localMaxima.minimumX := newX;
 388       findMinimumAndMaximumX(node->rightChild, AddressOf(localMaxima));
 389       If localMaxima.minimumX - x <= 40 Then
 390         Break;
 391       EndIf
 392     EndWhile
 393   EndIf
 394 EndFunction
 395 
 396 Function drawTree(PointerToTreeNode node) Which Returns Nothing Does
 397   drawRectangle(node->x - minimumX, node->y, 50, 50);
 398   If node->character Then
 399     Character output[4] := {'\'', node->character, '\'', 0};
 400     drawText(node->x + 5 - minimumX, node->y + 20, AddressOf(output[0]));
 401   EndIf
 402   Character output[8];
 403   output[0] := 0;
 404   convertIntegerToString(AddressOf(output[0]), node->frequencyOfCharacter);
 405   strcat(AddressOf(output[0]), "/");
 406   appendIntegerToString(AddressOf(output[0]), getLengthOfTheInput());
 407   drawText(node->x + 5 - minimumX, node->y + 40, AddressOf(output[0]));
 408   If node->leftChild Then
 409     drawText(node->x - minimumX - 10, node->y + 60, "0");
 410     drawLine(
 411              x1 := node->x + 25 - minimumX,
 412              x2 := node->x + 25 - minimumX,
 413              y1 := node->y + 50,
 414              y2 := node->y + 50 + 13,
 415             );
 416     drawLine(
 417              x1 := node->x + 25 - minimumX,
 418              x2 := node->leftChild->x + 25 - minimumX,
 419              y1 := node->y + 50 + 13,
 420              y2 := node->y + 50 + 13,
 421             );
 422     drawLine(
 423              x1 := node->leftChild->x + 25 - minimumX,
 424              x2 := node->leftChild->x + 25 - minimumX,
 425              y1 := node->y + 50 + 13,
 426              y2 := node->leftChild->y,
 427             );
 428     drawTree(node->leftChild);
 429   EndIf
 430   If node->rightChild Then
 431     drawText(node->x - minimumX + 50, node->y + 60, "1");
 432     drawLine(x1 := node->x + 25 - minimumX,
 433              y1 := node->y + 50,
 434              x2 := node->x + 25 - minimumX,
 435              y2 := node->y + 50 + 13);
 436     drawLine(x1 := node->x + 25 - minimumX,
 437              y1 := node->y + 50 + 13,
 438              x2 := node->rightChild->x + 25 - minimumX,
 439              y2 := node->y + 50 + 13);
 440     drawLine(x1 := node->rightChild->x + 25 - minimumX,
 441              y1 := node->y + 50 + 13,
 442              x2 := node->rightChild->x + 25 - minimumX,
 443              y2 := node->rightChild->y);
 444     drawTree(node->rightChild);
 445   EndIf
 446 EndFunction
 447 
 448 Function main() Which Returns Nothing Does
 449   clearScreen();
 450   Integer16 lengthOfInput := getLengthOfTheInput(), i := 0;
 451   If NDEBUG = 0 Then
 452     Character stringToBePrinted[64] := {0};
 453     strcat(AddressOf(stringToBePrinted[0]),
 454            "NDEBUG: The length of the input is: ");
 455     appendIntegerToString(AddressOf(stringToBePrinted[0]),
 456                            lengthOfInput);
 457     strcat(AddressOf(stringToBePrinted[0]), "\n");
 458     printString(AddressOf(stringToBePrinted[0]));
 459   EndIf
 460   While i < lengthOfInput Loop
 461     input[i] := getCharacterOfTheInput(i);
 462     i += 1;
 463   EndWhile
 464   input[lengthOfInput] := 0;
 465 
 466   If strlen(AddressOf(input[0])) = 0 Then
 467     printString("The input is empty!\n");
 468     Return;
 469   EndIf
 470 
 471   i := 0;
 472   While i < 256 Loop
 473     mapOfCodes[i] := PointerToCharacter(0);
 474     i += 1;
 475   EndWhile
 476 
 477   PointerToTreeNode array[32];
 478   Integer16 lengthOfTheArray := 0;
 479   i := 0;
 480   While i < lengthOfInput Loop
 481     Integer16 j := 0, haveWeFoundTheCharacterInTheArray := 0;
 482     While j < lengthOfTheArray Loop
 483       If array[j]->character = input[i] Then
 484         haveWeFoundTheCharacterInTheArray := 1;
 485         array[j]->frequencyOfCharacter += 1;
 486       EndIf
 487       j += 1;
 488     EndWhile
 489     If not(haveWeFoundTheCharacterInTheArray) Then
 490       array[lengthOfTheArray] := newTreeNode();
 491       array[lengthOfTheArray]->character := input[i];
 492       array[lengthOfTheArray]->frequencyOfCharacter := 1;
 493       lengthOfTheArray += 1;
 494     EndIf
 495     i += 1;
 496   EndWhile
 497 
 498   i := 0;
 499   While i < lengthOfTheArray Loop
 500     Character stringToBePrinted[64] := {0};
 501     strcat(AddressOf(stringToBePrinted[0]), "The character '");
 502     Integer16 indexOfCharacter := strlen(AddressOf(stringToBePrinted[0]));
 503     stringToBePrinted[indexOfCharacter] := array[i]->character;
 504     stringToBePrinted[indexOfCharacter + 1] := 0;
 505     strcat(AddressOf(stringToBePrinted[0]), "' has the frequency of ");
 506     appendIntegerToString(AddressOf(stringToBePrinted[0]),
 507                            array[i]->frequencyOfCharacter);
 508     strcat(AddressOf(stringToBePrinted[0]), ".\n");
 509     printString(AddressOf(stringToBePrinted[0]));
 510     i += 1;
 511   EndWhile
 512 
 513   Decimal32 ShannonEntropy := 0;
 514   i := 0;
 515   While i < lengthOfTheArray Loop
 516     ShannonEntropy -=
 517         (array[i]->frequencyOfCharacter / Decimal32(lengthOfInput)) *
 518         log2(array[i]->frequencyOfCharacter / Decimal32(lengthOfInput));
 519     i += 1;
 520   EndWhile
 521   output[0] := 0;
 522   strcat(AddressOf(output[0]), "The Shannon Entropy of the input string is: ");
 523   convertDecimalToString(AddressOf(output[0]) + strlen(AddressOf(output[0])),
 524                          ShannonEntropy);
 525   strcat(AddressOf(output[0]), " bits/symbol.\n");
 526   printString(AddressOf(output[0]));
 527 
 528   While lengthOfTheArray > 1 Loop
 529     Integer16 minimum := 0, secondMinimum := 0;
 530 
 531     Integer16 i := 0;
 532     If NDEBUG = 0 Then
 533       Character stringToBePrinted[64] := {0};
 534       strcat(AddressOf(stringToBePrinted[0]),
 535              "NDEBUG: The length of the array is ");
 536       appendIntegerToString(AddressOf(stringToBePrinted[0]),
 537                              lengthOfTheArray);
 538       strcat(AddressOf(stringToBePrinted[0]), ".\n");
 539       printString(AddressOf(stringToBePrinted[0]));
 540     EndIf
 541     While i < lengthOfTheArray Loop
 542       If NDEBUG = 0 Then
 543         Character stringToBePrinted[64] := {0};
 544         strcat(AddressOf(stringToBePrinted[0]),
 545                "NDEBUG: The tree at the index #");
 546         appendIntegerToString(AddressOf(stringToBePrinted[0]),
 547                                i);
 548         strcat(AddressOf(stringToBePrinted[0]), " is the TreeNode #");
 549         appendIntegerToString(AddressOf(stringToBePrinted[0]),
 550                                (array[i] - AddressOf(treeNodes[0])) /
 551                                    SizeOf(TreeNode));
 552         strcat(AddressOf(stringToBePrinted[0]), ".\n");
 553         printString(AddressOf(stringToBePrinted[0]));
 554       EndIf
 555       If not(isTreeNodeWithinBounds(array[i])) Then
 556         segmentationFault();
 557         asm("unreachable");
 558       EndIf
 559       i += 1;
 560     EndWhile
 561 
 562     i := 0;
 563     While i < lengthOfTheArray Loop
 564       If array[i]->frequencyOfCharacter <
 565           array[minimum]->frequencyOfCharacter Then
 566         minimum := i;
 567       EndIf
 568       i += 1;
 569     EndWhile
 570 
 571     i := minimum = 0 ? 1 : 0;
 572     secondMinimum := i;
 573     While i < lengthOfTheArray Loop
 574       If array[i]->frequencyOfCharacter <
 575               array[secondMinimum]->frequencyOfCharacter and
 576           i != minimum Then
 577         secondMinimum := i;
 578       EndIf
 579       i += 1;
 580     EndWhile
 581 
 582     If NDEBUG = 0 Then
 583       Character stringToBePrinted[64] := {0};
 584       strcat(AddressOf(stringToBePrinted[0]),
 585              "NDEBUG: The minimum and the second minimum are ");
 586       appendIntegerToString(AddressOf(stringToBePrinted[0]),
 587                              minimum);
 588       strcat(AddressOf(stringToBePrinted[0]), " and ");
 589       appendIntegerToString(AddressOf(stringToBePrinted[0]),
 590                              secondMinimum);
 591       strcat(AddressOf(stringToBePrinted[0]), ".\n");
 592       printString(AddressOf(stringToBePrinted[0]));
 593     EndIf
 594 
 595     If NDEBUG = 0 Then
 596       Character stringToBePrinted[64] := {0};
 597       strcat(AddressOf(stringToBePrinted[0]), "NDEBUG: Joining the TreeNode #");
 598       appendIntegerToString(AddressOf(stringToBePrinted[0]),
 599                              (array[minimum] - AddressOf(treeNodes[0])) /
 600                                  SizeOf(TreeNode));
 601       strcat(AddressOf(stringToBePrinted[0]), " with the TreeNode #");
 602       appendIntegerToString(AddressOf(stringToBePrinted[0]),
 603                              (array[secondMinimum] - AddressOf(treeNodes[0])) /
 604                                  SizeOf(TreeNode));
 605       strcat(AddressOf(stringToBePrinted[0]), ".\n");
 606       printString(AddressOf(stringToBePrinted[0]));
 607     EndIf
 608 
 609     PointerToTreeNode sumOfTheTwoMostFrequent := newTreeNode();
 610     sumOfTheTwoMostFrequent->frequencyOfCharacter
 611          := array[minimum]->frequencyOfCharacter +
 612             array[secondMinimum]->frequencyOfCharacter;
 613     sumOfTheTwoMostFrequent->leftChild := array[minimum];
 614     sumOfTheTwoMostFrequent->rightChild := array[secondMinimum];
 615 
 616     If NDEBUG = 0 Then
 617       Character stringToBePrinted[64] := {0};
 618       strcat(AddressOf(stringToBePrinted[0]),
 619              "NDEBUG: The new TreeNode has the frequency of: ");
 620       appendIntegerToString(AddressOf(stringToBePrinted[0]),
 621                              sumOfTheTwoMostFrequent->frequencyOfCharacter);
 622       strcat(AddressOf(stringToBePrinted[0]), ".\n");
 623       printString(AddressOf(stringToBePrinted[0]));
 624     EndIf
 625 
 626     If not(MAINTAIN_COMPATIBILITY_WITH_JAVASCRIPT_IMPLEMENTATION) Then
 627       array[minimum] := sumOfTheTwoMostFrequent;
 628     EndIf
 629 
 630     // Delete the second minimum from the array...
 631     i := secondMinimum;
 632     While i < lengthOfTheArray - 1 Loop
 633       array[i] := array[i + 1];
 634       i += 1;
 635     EndWhile
 636     lengthOfTheArray -= 1;
 637     If not(MAINTAIN_COMPATIBILITY_WITH_JAVASCRIPT_IMPLEMENTATION) Then
 638       Continue;
 639     EndIf
 640     // Delete the first minimum from the array...
 641     If minimum >
 642         secondMinimum Then   // If the first minimum moved while we were
 643                              // deleting the second minimum from the array.
 644       minimum -= 1;
 645     EndIf
 646     i := minimum;
 647     While i < lengthOfTheArray - 1 Loop
 648       array[i] := array[i + 1];
 649       i += 1;
 650     EndWhile
 651     array[lengthOfTheArray - 1] := sumOfTheTwoMostFrequent;
 652   EndWhile
 653 
 654   If NDEBUG = 0 Then
 655     Character stringToBePrinted[128] := {0};
 656     strcat(AddressOf(stringToBePrinted[0]),
 657            "NDEBUG: The frequency of the root node is ");
 658     appendIntegerToString(AddressOf(stringToBePrinted[0]),
 659                            array[0]->frequencyOfCharacter);
 660     strcat(AddressOf(stringToBePrinted[0]),
 661            ". If the algorithm is correctly implemented, it should be ");
 662     appendIntegerToString(AddressOf(stringToBePrinted[0]),
 663                            lengthOfInput);
 664     strcat(AddressOf(stringToBePrinted[0]), ".\n");
 665     printString(AddressOf(stringToBePrinted[0]));
 666   EndIf
 667 
 668   printString("The tree has been constructed, let us assign Huffman codes to "
 669               "characters:\n");
 670   assignCode("", array[0]);
 671 
 672   Integer16 lengthOfTheOutput := 0;
 673   i := 0;
 674   While i < lengthOfInput Loop
 675     lengthOfTheOutput += strlen(mapOfCodes[input[i]]);
 676     i += 1;
 677   EndWhile
 678   output[0] := 0;
 679   strcat(AddressOf(output[0]), "The length of the encoded string is: ");
 680   appendIntegerToString(AddressOf(output[0]), lengthOfTheOutput);
 681   strcat(AddressOf(output[0]), " bits.\n");
 682   printString(AddressOf(output[0]));
 683 
 684   output[0] := 0;
 685   strcat(AddressOf(output[0]),
 686          "The average length of the symbol in the Huffman code is: ");
 687   convertDecimalToString(AddressOf(output[0]) + strlen(AddressOf(output[0])),
 688                          Decimal32(lengthOfTheOutput) / lengthOfInput);
 689   strcat(AddressOf(output[0]), " bits/symbol.\n");
 690   printString(AddressOf(output[0]));
 691 
 692   output[0] := 0;
 693   i := 0;
 694   While i < lengthOfInput Loop
 695     strcat(AddressOf(output[0]), mapOfCodes[input[i]]);
 696     i += 1;
 697   EndWhile
 698   strcat(AddressOf(output[0]), "\n");
 699   printString("The Huffman code of the input is:\n");
 700   printString(AddressOf(output[0]));
 701 
 702   setCoordinates(array[0], 0, 0, 10 * shl(1, getHeight(array[0])));
 703   InstantiateStructure Maxima globalMaxima;
 704   globalMaxima.minimumX := globalMaxima.maximumX := 0;
 705   findMinimumAndMaximumX(array[0], AddressOf(globalMaxima));
 706   minimumX := globalMaxima.minimumX;
 707   maximumX := globalMaxima.maximumX;
 708   drawTree(array[0]);
 709   setDiagramWidth(maximumX - minimumX + 55);
 710   setDiagramHeight(getHeight(array[0]) * 75);
 711 
 712   freeUpTheTree(array[0]);
 713 
 714   Character stringToBePrinted[64] := {0};
 715   strcat(AddressOf(stringToBePrinted[0]), "Decoding the output...\n");
 716   printString(AddressOf(stringToBePrinted[0]));
 717 
 718   Integer16 j := 0, k := 0;
 719   While j < strlen(AddressOf(output[0])) - 1 Loop
 720     i := 0;
 721     If NDEBUG = 0 Then
 722       printString(
 723           "NDEBUG: We are entering the loop for decoding the output!\n");
 724     EndIf
 725     While (mapOfCodes[i] = 0 or strncmp(AddressOf(output[j]), mapOfCodes[i],
 726                                        strlen(mapOfCodes[i]))) and
 727         i < 256 Loop
 728       If NDEBUG = 0 Then
 729         If mapOfCodes[i] = 0 Then
 730           printString("NDEBUG: Skipping the character because it's NULL.\n");
 731         Else
 732           printString(
 733               "NDEBUG: Skipping the character because it doesn't match!\n");
 734         EndIf
 735       EndIf
 736       i += 1;
 737     EndWhile
 738     If i = 256 Then
 739       printString("ERROR: Cannot find the beginning of the current string in "
 740                   "the map of codes!\n");
 741       Return;
 742     EndIf
 743     stringToBePrinted[0] := 0;
 744     strcat(AddressOf(stringToBePrinted[0]), mapOfCodes[i]);
 745     strcat(AddressOf(stringToBePrinted[0]), "=>");
 746     Character stringToBeAdded[5] := {'\'', i, '\'', '\n', 0};
 747     strcat(AddressOf(stringToBePrinted[0]), AddressOf(stringToBeAdded[0]));
 748     printString(AddressOf(stringToBePrinted[0]));
 749     j += strlen(mapOfCodes[i]);
 750     If i != getCharacterOfTheInput(k) Then
 751       printString("ERROR: The decoded output does not match the input!\n");
 752       Break;
 753     EndIf
 754     k += 1;
 755   EndWhile
 756 EndFunction
 757