/************************************************************************ SYSTEM/MACHINE - IAS V2.0 / PDP-11/70 AUTHOR - JN GUIDI DATE - 06-DEC-78 TYPE/LANGUAGE - MAIN PROCEDURE / ARTHUR COSTONS PL/I V1.0J RESIDENCE - ELIZA.PLI -DATA FILES- DOCTOR.KEY DOCTOR.NUM DOCTOR.CON DOCTOR.RPL RESTRICTIONS - NOT TO BE USED BY PARANOID USERS ABSTRACT - THE ORIGINAL ELIZA PROGRAM WAS WRITTEN IN LISP BY JOSEPH WEIZENBAUM (MIT). THIS PROGRAM WAS INSPIRED BY STEVE NORTH'S ARTICLE (CREATIVE COMPUTING). THIS PL/I PROGRAM WAS WRITTEN BY JOHN GUIDI (THE JACKSON LABORATORY) TO HELP WHILE AWAY THE WEE HOURS OF THE NIGHT. BESIDES, IT WAS A GOOD EXCUSE TO USE ARTHUR COSTON'S PL/I COMPILER. GOOD SHOW ARTHUR, WELL DONE !! UPDATE - THE TEXT FILES WERE REPLACED WITH TEXT FROM THE FALL '78 DECUS TAPES. CONGRATULATIONS YE WHO WROTE THE DOCTOR PROGRAM IN TECO, AND THANKS FOR THE TEXT FILES. ************************************************************************ THERE ARE 4 FILES INVOLVED: 1) DOCTOR.KEY - THIS FILE CONATINS A LIST OF ALL THE KEYWORDS WHICH ELIZA CAN RECOGNIZE. 2) DOCTOR.RPL - THIS FILE CONTAINS A LIST OF ALL THE REPLIES WHICH ELIZA KNOWS. 3) DOCTOR.NUM - FOR EACH KEYWORD, THE CORRESPONDING DOCTOR.NUM RECORD CONTAINS THE RECORD OF THE FIRST REPLY FOR THIS KEYWORD, AND THE NUMBER OF REPLIES AVAILABLE. 4) DOCTOR.CON - THIS FILE CONTAINS CONJUGATES, AND THE CONJUGATE'S PAIR IN THE NEXT RECORD. ***********************************************************************/ ELIZA: PROCEDURE OPTIONS (MAIN); DCL I,J,K,CONPOS FIXED BIN (15); DCL NKEY,NCON,NREP FIXED BIN (15); DCL REPID(51),REPTOT(51) FIXED BIN(15); DCL REPUSE(51) STATIC FIXED BIN(15) INITIAL((51)0); DCL KEYWORD(51) CHAR (15) VARYING; DCL CONJUG(15,2) CHAR (10) VARYING; DCL REPLY(144) CHAR (80) VARYING; DCL RESPONSE CHAR (80) VARYING; DCL OUTBUF CHAR (80) VARYING; DCL ALPHA CHAR(1); DCL BYTE BIT(8); DCL KEYID FIXED BIN(15); DCL KEYFILE FILE STREAM INPUT ENV(V CTLIMP); DCL CONFILE FILE STREAM INPUT ENV(V CTLIMP); DCL REPFILE FILE STREAM INPUT ENV(V CTLIMP); DCL NUMFILE FILE STREAM INPUT ENV(V CTLIMP); DCL EXIT CONDITION; /* IF THE KEYWORD FILE, THE CONJUGATE FILE, OR THE REPLY FILE CHANGES IN SIZE, ONE MUST CHANGE THE ARRAY DIMENSIONS. IN ADDITION TO CHANGING THE ARRAY DIMENSIONS, SET THESE VALUES TO THE MAXIMUM DIMENSIONS. */ NKEY=51; NCON=15; NREP=144; /*************************** SEED THE ARRAYS ****************************/ /* SEED THE KEYWORD ARRAY FROM THE APPROPRIATE FILE */ OPEN FILE(KEYFILE) TITLE('DB0:DOCTOR.KEY'); DO I=1 TO NKEY; GET FILE(KEYFILE) EDIT (KEYWORD(I)) (A); END; CLOSE FILE(KEYFILE); /* NOW SEED THE CONJUGATION ARRAY */ OPEN FILE(CONFILE) TITLE('DB0:DOCTOR.CON'); DO I=1 TO NCON; DO J=1 TO 2; GET FILE(CONFILE) EDIT (CONJUG(I,J)) (A); END; END; CLOSE FILE(CONFILE); /* NOW WE NEED TO SEED THE REPLIES */ OPEN FILE(REPFILE) TITLE('DB0:DOCTOR.RPL'); DO I=1 TO NREP; GET FILE(REPFILE) EDIT (REPLY(I)) (A); END; CLOSE FILE(REPFILE); /* SEED THE REPLY POINTER ARRAYS. RESID IS ACTUAL POINTER INTO REPLY(NREP) ARRAY. REPTOT IS TOTAL NUMBER OF REPLIES FOR THIS KEYWORD. REPUSE IS BUMPED UP 1 EACH TIME A REPLY IS USED. (KEEPS THE CONVERSATION FROM GETTING TOO DULL!) */ OPEN FILE(NUMFILE) TITLE('DB0:DOCTOR.NUM'); DO I=1 TO NKEY; GET FILE(NUMFILE) LIST(REPID(I),REPTOT(I)); END; /************** SET UP EXIT CONDITION, PRINT INITAL STATEMENT ***********/ /* WHENEVER THE PATIENT TYPES 'SHUT UP', WE SAY GOODNIGHT, AND CLOSE UP SHOP! */ ON CONDITION(EXIT) BEGIN; PUT SKIP LIST('GOODBYE'); GOTO BYE; END; /* PRINT OUT OUR OPENING STATEMENT */ PUT SKIP LIST ('THIS IS THE PDP-11 ELIZA PROGRAM, WHAT''S YOUR PROBLEM?'); /*************** HERE IS WHERE THE WORK IS DONE ************************* 1) PROMPT THE USER, OBTAIN HIS RESPONSE 2) REMOVE ANY APHOSTROPHES FROM USERS RESPONSE 3) PAD BOTH SIDES OF USERS RESPONSE 4) CONVERT LOWERCASE CHARACTERS TO UPPERCASE 5) SEARCH KEYWORD ARRAY FOR THE FIRST MATCH 6) CONJUGATE STRING TO RIGHT OF USERS RESPONSE IF KEYWORD FOUND 7) GET REPLY STRING USING VALUES IN REPID (START OF REPLIES), REPUSE (REPLY TO USE), AND REPTOT (NUMBER OF REPLIES AVAILABLE) 8) CONCATENATE USERS RESPONSE STRING TO REPLY STRING IF NEEDED 9) CONVERT LOWERCASE REPLY STRING TO UPPERCASE CHARCTERS *************************************************************************/ /* NOW WE PROMPT THE PATIENT, AND THEN TRY AND MATCH HIS RESPONSE WITH OUR KEYWORD LIST */ DO WHILE ('1'B); PUT SKIP LIST('>'); GET EDIT (RESPONSE) (A); /* PAD BOTH SIDES OF RESPONSE WITH SPACES */ RESPONSE=' '!!RESPONSE; RESPONSE=RESPONSE!!' '; IF INDEX(RESPONSE,' SHUT UP ')^=0 THEN SIGNAL CONDITION(EXIT); /* GET RID OF ALL APOSTROPHES IN PATIENTS REPLY */ SIZE=LENGTH(RESPONSE); DO I=1 TO SIZE-1; ALPHA=SUBSTR(RESPONSE,I,1); J=UNSPEC(ALPHA); IF J=39 THEN DO; SIZE=SIZE-1; DO J=I+1 TO SIZE+1; SUBSTR(RESPONSE,J-1,1)=SUBSTR(RESPONSE,J,1); END; END; END; SUBSTR(RESPONSE,1)=SUBSTR(RESPONSE,1,SIZE); /************************************************************************/ /* NOW MAKE CERTAIN THAT RESPONSE IS ALL UPPERCASE CHARACTERS */ DO I=1 TO LENGTH(RESPONSE); ALPHA=SUBSTR(RESPONSE,I,1); IF (ALPHA >= 'a' & ALPHA <= 'z') THEN DO; BYTE=UNSPEC(ALPHA); BYTE=BYTE&'11011111'B; UNSPEC(ALPHA)=UNSPEC(BYTE); SUBSTR(RESPONSE,I,1)=ALPHA; END; END; /***********************************************************************/ /* AT THIS POINT WE HAVE PATIENT'S RESPONSE. WE MUST NOW SEARCH THE KEYWORD ARRAY FOR THE FIRST MATCH. NOTE! THIS IS WHY THE KEYWORDS ARE ENTERED INTO THE ARRAY IN ORDER OF IMPORTANCE */ KEYID=0; J=0; DO WHILE (J=0 & KEYID0. IF J=0, NO KEYWORD FOUND. TAKE THE RIGHT PART OF THE STRING, AND CONJUGATE IT. IF NECESSARY. */ IF J>0 THEN DO; SUBSTR(RESPONSE,1)=SUBSTR(RESPONSE,J+LENGTH(KEYWORD(KEYID))); RESPONSE=' '!!RESPONSE; /* NOW SEARCH FOR ANY CONJUGATE PAIRS IN THE REMAINING STRING */ OUTBUF=RESPONSE; DO I=1 TO NCON; DO WHILE (INDEX(RESPONSE,CONJUG(I,1))^=0); CONPOS=INDEX(RESPONSE,CONJUG(I,1)); /* PUSH STRING PRECEDING CONJUGATE */ IF CONPOS ^=1 THEN SUBSTR(OUTBUF,1)=SUBSTR(RESPONSE,1,CONPOS-1); /* NOW CONCATENATE THE CONJUGATE'S PAIR */ OUTBUF=SUBSTR(OUTBUF,1,CONPOS-1)!!CONJUG(I,2); /* NOW CONCATENATE THE REST OF THE STRING */ OUTBUF=SUBSTR(OUTBUF,1,CONPOS+LENGTH(CONJUG(I,2))) !!SUBSTR(RESPONSE,CONPOS+LENGTH(CONJUG(I,1))); /* NOW PUT OUTBUF BACK INTO RESPONSE SO WE CAN CONJUGATE ANY OTHER PAIRS */ SUBSTR(RESPONSE,1)=SUBSTR(OUTBUF,1); END; END; END; /**************************************************************************/ /* 1) GET REPID(KEYID). THIS IS THE FIRST ELEMENT OF THE REPLY(NREP) ARRAY FOR THE MATCHED KEYWORD. 2) GET REPTOT(KEYID). THIS IS THE NUMBER OF AVAILABLE REPLIES FOR THIS KEYWORD MATCH. 3) CHECK REPUSE(KEYID) TO SEE WHAT THE LAST REPLY WAS. 4) CREATE THE REPLY STRING AND PRINT IT */ I=REPID(KEYID)+REPUSE(KEYID); /* BUMP THE REPUSE UP IF THERE ARE MORE REPLIES, OTHERWISE SET IT BACK TO THE BEGINING (0) */ REPUSE(KEYID)=REPUSE(KEYID)+1; IF REPUSE(KEYID)=REPTOT(KEYID) THEN REPUSE(KEYID)=0; OUTBUF=REPLY(I); IF INDEX(OUTBUF,'*')^=0 THEN DO; OUTBUF=SUBSTR(OUTBUF,1,INDEX(OUTBUF,'*')-1); OUTBUF=OUTBUF!!RESPONSE; END; /* NOW MAKE CERTAIN THAT OUTBUF IS ALL UPPERCASE CHARACTERS */ DO I=1 TO LENGTH(OUTBUF); ALPHA=SUBSTR(OUTBUF,I,1); IF (ALPHA >= 'a' & ALPHA <= 'z') THEN DO; BYTE=UNSPEC(ALPHA); BYTE=BYTE&'11011111'B; UNSPEC(ALPHA)=UNSPEC(BYTE); SUBSTR(OUTBUF,I,1)=ALPHA; END; END; PUT SKIP LIST(OUTBUF); END; /************************************************************************/ BYE: END ELIZA;