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