procedure PERM (A, k, n) { if (R6 < 0) { /* Location 004 */ call PRINTSTRING () /* Print the current string permutation. */ /* Here we return from PERM(). This is done by popping the stack and restoring the previous stack frame. If all the iterations are complete in the previous call frame, then loop and return again (until the stack is empty). */ L160: do { if (R7 <= 8) { /* Stack empty? All permutations generated? */ L235: Print blank line Print R0 /* Total # of permutations generated. */ EXIT } L167: R7 = R7 - 1 /* Pop current stack frame and restore local variables from previous stack frame. */ X = fract (R7) * 10 /* i.k */ R6 = X R5 = int (X) /* Value of i */ R6 = (R6 - R5) * 10 /* Value of k (i.k - i = 0.k) */ R5 = R5 - 1 L197: } while (R5 < 0) L194: /* R5 >= 0, so proceed to the next iteration to generate a new permutation. In the calculator program, this is done by branching to 009 (immediately below in this PDL). */ } /******************************************************************************* The following code (locations 007 through 106): (1) Swaps characters i and k in string A (2) Recursively calls PERM (A, k-1, n) *******************************************************************************/ /* Locations 007 through 106 */ R5 = R6 L009: if (R6 != R5) { /* Location 014 */ R4 = antilog (R6) /* Location 019 */ R3 = antilog (R5) /* Location 027 */ /* Location 040 */ R2 = int (fract (A / R3 / 10) * 10) R1 = -R2 /* Location 042 */ /* Location 059 */ X = int (fract (A / R4 / 10) * 10) R1 = R1 + X /* Location 060 */ R2 = R2 - X /* Location 062 */ /* The following two lines swap the two characters in A. */ A = A + (R1 * R3) /* Location 071 */ A = A + (R2 * R4) /* Location 079 */ } L083: /* Update A, local variables in current stack frame. */ A = int (A) + R5/10 + R6/100 /* Location 094 */ /* Push A/variables onto stack and ... */ PUSH (A) R6 = R6 - 1 /* ... "recursively" call PERM (A, k-1, n) */ PERM (A, k-1, n) /* Location 106 */ } /******************************************************************************* PRINTSTRING() - print the current string permutation. The printer has four 5-character registers for a total line width of 20. Print the string right-justified in the middle 10 characters (registers #2 and #3), leaving blanks on either side (registers #1 and #4). NOTE that, in the calculator program, this function is in-line code, and is NOT a subroutine. I've extracted it to make the main-line PDL clearer. *******************************************************************************/ procedure PRINTSTRING () { L107: /* First, right-justify the string in the two 5-character printer registers. R1 will contain the rightmost 5 characters (actually indices) in its 5-digit fraction, with leading zeroes if the string length is less than 5. R2 will contain the preceding characters in its 5-digit fraction, with leading zeroes if the string length is less than 10. (The string length is ALWAYS between 1 and 9, so R2 will have at least one leading zero.) */ X = A / 100,000 /* X = A[1..N-5].A[N-4..N]ik */ R1 = fract (X) /* R1 = 0.A[N-4..N]ik */ R2 = X / 100,000 /* R2 = 0.A[1..N-5] */ L131: if (R19 > 5) { /* Load left half of right-justified string into printer register for characters 6-10. R3 = 0 X = ASSEMBLEWORD (5, R2 = 0.A[1..N-5], R3 = 0) Printer's Alphanumeric Register #2 = X } L143: R2 = R1 R3 = 0 X = ASSEMBLEWORD (5, R2 = 0.A[N-4..N]ik, R3 = 0) Printer's Alphanumeric Register #3 = X L156: Print the alphanumeric registers R19 = R19 + 1 /* Increment the number of permutations generated. */ } ******************************************************************************** A permutation algorithm from Ellis Horowitz's and Sartaj Sahni's FUNDAMENTALS OF DATA STRUCTURES. The algorithm, coded in the book's SPARKS pseudo-programming language, is found in Chapter 1, in the subsection about recursion. This is apparently NOT the algorithm or pseudocode I was working from when I wrote my calculator program. procedure PERM (A, k, n) if k = n then [print (A); return] B <- A for i <- k to n do call INTERCHANGE (A, k, i) call PERM (A, k+1, n) A <- B end end PERM ******************************************************************************** Partial reverse-engineering with actual values: 1234567 A = "BCDEFGH" k = 3 [R6] i = 5 [R5] **************************************** Code below is: call INTERCHANGE (A, k, i) /* Exchange k-th and i-th chars */ but it seems to exchange the k-1-th and i-1-th chars. In the example, exchanging characters 3 and 5 actually exchanges characters 2 and 4. (Counting from left; counting from right: 6 and 4.) **************************************** ---------- Location 017: R4 <- antilog(R6) = 10**3 = 1000 Recall A 1234567.xyz / R3 <- antilog(R5) = 10**5 = 100000 [= 12.34567xyz] / 10 = 1.234567xyz FRACT = .234567xyz * 10 = 2.34567xyz INT = 2 R2 <- 2 +/- = -2 R1 <- -2 x/t ==> -2 to T and A to X 1234567.xyz / R4 [antilog (R6) = 1000] [= 1234.567xyz] / 10 = 123.4567xyz FRACT = .4567xyz * 10 = 4.567xyz INT = 4 ---------- Location 60: R1 := R1 + 4 [-2 + 4 = 2] R2 := R2 - 4 [2 - 4 = -2] X <- R1 * R3 [R1 * 100000 = 200000] 200000 *R7 = *R7 + 200000 1234567.xyz [*R7 = 1434567.xyz] X <- R2 * R4 [R2 * 1000 = -2000] *R7 = *R7 - 2000 1234567.xyz [*R7 = 1432567.xyz] Recall R6 [k = 3] / 100 [= .03] + Recall R5 [= 5] / 10 [= .50] + *R7 INT [= 1432567] = 1432567.53 Store *R7 [update current stack frame] ---------- Location 100: Increment R7 (SP) Store *R7 [duplicate in new stack frame?] R6 := R6 - 1 [k-1] [x still contains 1432567.53] RESET [call PERM (A, k-1, n) or PERM (A, 2, 7)] ---------- Location 107: Prepare to print ...