& & PL-516 VERSION OF 99 BEERS ON THE WALL & & TYPE 99 BOTTLES ON THE ASR-33 & .COMPCONST CR = '215, & OCTAL CARRIAGE-RETURN CHARACTER LF = '212; & OCTAL LINE-FEED CHARACTER .COMPCONST TRUE  = -1; .COMPCONST NBOTTLES = 99; .INTEGER BOTTLES;   & COUNT THEM .INTEGER STARTLINE& FLAG - AT START OF LINE & & PL-516 HAS NO LIBRARIES FOR I/O (OR ANYTHING ELSE) & WE'RE PROGRAMMING ON THE BARE METAL HERE... & & SO START WITH SOME SIMPLE ROUTINES TO OUTPUT & CHARACTERS & & & THIS IMPLEMENTS A TEST THAT THE CHARAACTER & PASSED AS AN ARGUMENT IS A LETTER & .CONDITIONAL .PROCEDURE LETTER; .WHEN .RANGE $$.TO $$.THEN .EXITTRUE; & & TYPE ONE CHARACTER ON THE ASR & & THERE'S SOME CRUFTY CODE HERE BECAUSE PL-516 & DATES FROM AN ERA WHEN THE USUAL I/O DEVICE WAS & AN ASR-33 (A MECHANICAL TELETYPE) THAT HAD NO & LOWER-CASE LETTERS, SO ALTHOUGH THE ASCII CODES & WE NOW USE AS LOWER-CASE LETTERS COULD BE SENT & THEY'D PRINT AS UPPER-CASE. & FOR SOME REASON THE SOURCE INPUT READER OF THE & PL-516 COMPILER DISCARDS LOWER-CASE LETTERS, EVEN & IN STRINGS AND CHARACTER CONSTANTS, WHICH IS & WHY THE CODE BELOW IS ALL IN UPPER-CASE. & & IN ORDER TO GET THE CORRECT CASE OF TEXT & PRINTED OUT I CONVERT ALMOST EVERYTHING TO LOWER- & CASE IN THIS 'TYPE' ROUTINE, EXCEPT I LEAVE & THE FIRST CHARACTER OF EACH LINE AS UPPER-CASE & .PROCEDURE TYPE; .INTEGER C; .BEGIN      C := @;   @ := .IF LETTER(.CLEFT @) .AND   STARTLINE .Z .THEN   C + '040 & MAKE IT LOWER CASE   .ELSE C;   & ELSE USE AS IS      &   & EMBEDDED ASSEMBLY LANGUAGE INSTRUCTIONS   & TO ACTUALLY OUTPUT TO THE ASR   &   %SKS,'104; & SKIP IF ASR NOT BUSY   %JMP,*-1;  & LOOP UNTIL NOT BUSY   %OCP,'104; & ASR TO OUTPUT MODE   %OTA,'4;   & OUTPUT CHARACTER IN A REGISTER   %JMP,*-1;  & LOOP UNTIL READY      STARTLINE := .Z;   @ := C& RESTORE ACCUMULATOR (FOR CHARACTER IN OTHER HALF) .END; & & TYPE THE TWO 8-BIT CHARACTERS IN THE 16-BIT ARGUMENT & .PROCEDURE TYPE2; .BEGIN   TYPE(.SWOP @); & UPPER CHARACTER IN A REG.   TYPE(.SWOP @); & AND THE LOWER ONE .END; & & TYPE CARRIAGE-RETURN, LINE-FEED TO GET TO START OF LINE & .PROCEDURE NEWLINE; .BEGIN   TYPE(<CR,LF>);   STARTLINE := TRUE; .END; & & TYPE A STRING & THE STRING IS TERMINATED BY AN ASTERIX & (C-STYLE NULL-TERMINATION WOULD HAVE BEEN MORE & SENSIBLE, BUT PL-516 DOESN'T DO THAT, SO THE & TERMINATION NEEDS TO BE A PRINTABLE CHARACTER) & .PROCEDURE TYPESTRING; .INTEGER P& POINTER INTO STRING .ARRAY STRING[0]; & ARRAY WORD THAT WILL POINT TO STRING .BEGIN   %STASTRING& POINT AT THE STRING TO TYPE   .FOR P := .Z .DO .BEGIN     INDEX := P .SHSRA 1; & DIVIDE P BY TWO     @ := STRING[#];      & GET TWO CHARACTERS          & IF P WAS ODD THEN THE SHIFT (THAT DIVIDED     & BY TWO) WILL HAVE SET THE CARRY BIT     .UNLESS .CSET .THEN     @ := .SWOP @;          & CLEAR THE UPPER HALF OF THE ACCUMULATOR     & AND COMPARE TO THE STRING TERMINATION     .WHEN .CLEFT @ = $$* .THEN     .EXIT;          TYPE(@);   .END; .END; & & TYPE A POSITIVE INTEGER IN DECIMAL & .PROCEDURE TYPEDECIMAL; .INTEGER N;      & THE NUMBER STILL TO BE PRINTED .INTEGER TYPING& FLAG (SUPPRESS LEADING ZEROS) .COMPCONST NPOWER=-5; & ARRAYS HAVE NEGATIVE INDICES .ARRAY POWER[NPOWER](10000,1000,100,10,1); .BEGIN   N := @;       & SAVE THE NUMBER TO PRINT   TYPING := .Z&       & SPECIAL-CASE ZERO   .IF N .Z .THEN   TYPE($$0)   .ELSE .BEGIN     .FOR # := NPOWER .DO .BEGIN       .WHEN TYPING .NZ .OR       N .GE POWER[#] .THEN .BEGIN         TYPE(N/POWER[#]+$$0);         N := .B& PICK UP THE REMAINDER FROM THE DIVIDE         TYPING := TRUE;       .END;     .END;   .END; .END; & & TYPEBOTTLE DEALS WITH PRINTING "N BOTTLE(S)" & DEALING WITH THE CASES OF ONE BOTTLE (NOT PLURAL) & AND ZERO BOTTLES ("NO MORE BOTTLES") &  .PROCEDURE TYPEBOTTLE; .INTEGER BOT; .BEGIN   BOT := @;   .IF .Z .THEN .BEGIN     TYPESTRING("NO MORE*");   .END .ELSE   TYPEDECIMAL(BOT);   TYPESTRING(" BOTTLE*");   .WHEN BOT .NE .THEN   TYPE($$S); .END; & & PRINT OUT ONE ENTIRE VERSE, THE ARGUMENT & IS THE NUMBER OF BOTTLES (AT THE START OF & THE VERSE) & .PROCEDURE VERSE; .INTEGER BOT; .BEGIN   BOT := @;   TYPEBOTTLE(BOT);   TYPESTRING(" OF BEER ON THE WALL, *");   TYPEBOTTLE(BOT);   TYPESTRING(" OF BEER.*");   NEWLINE;   .IF BOT .Z .THEN .BEGIN     TYPESTRING("GO TO THE STORE AND BUY SOME MORE, *");     BOT := NBOTTLES;   .END .ELSE .BEGIN     TYPESTRING("TAKE ONE DOWN AND PASS IT AROUND, *");     BOT := BOT-1;   .END;   TYPEBOTTLE(BOT);   TYPESTRING(" OF BEER ON THE WALL.*");   NEWLINE; .END; & & AND FINALLY THE MAIN PROGRAM & .ORIGIN '1000; .BEGIN   NEWLINE;      .FOR BOTTLES := NBOTTLES .STEPDOWN -1 .UNTIL .DO .BEGIN     VERSE(BOTTLES);     NEWLINE;   .END;    .END;