00050 .PR POINT .PR 00100 .COMMENT SISTERS, COUSINS AND AUNTS - MODEL SOLUTION .COMMENT 00120 ( .MODE .PERSON = .STRUCT(.STRING NAME, .BOOL SEX, .INT COUNT, .BITS UP 00130 , .REF .PERSON PA, MA, NEXTHASH) 00140 ; .REF .PERSON NOBODY = .NIL 00150 ; .INT HASHSIZE = 43 00152 ; .INT BITSWIDTH = (MAXINT=32767!16!32) 00160 ; .LOC [0:HASHSIZE-1] .REF .PERSON HASHTABLE 00170 # PERSONS HASHING TO THE SAME HASHTABLE ELEMENT WILL BE CHAINED 00180 USING THE 'NEXTHASH' FIELD # 00190 ; .FOR I .FROM 0 .TO HASHSIZE-1 00200 .DO HASHTABLE[I] := NOBODY .OD 00210 ; .BOOL MALE = .TRUE, FEMALE = .FALSE, CHECK = .TRUE, NOCHECK = .FALSE 00220 ; .PROC HASHIN = (.STRING NAME, .BOOL SEX, CHECK).REF .PERSON: 00230 # RETURNS EXISTING .REF .PERSON FROM HASHTABLE (CHECKING EXISTING SEX IF 'CHECK'), 00240 OR CREATES A NEW ONE AS REQUIRED. 00250 AN EMPTY 'NAME' RETURNS 'NOBODY' # 00260 .IF NAME="" 00270 .THEN NOBODY 00280 .ELSE .LOC .INT HASHNO := 0 00290 ; .FOR I .TO .UPB NAME 00300 .DO HASHNO +:= .ABS NAME[I] .OD 00310 ; .LOC .REF .REF .PERSON PTR := HASHTABLE[HASHNO .MOD HASHSIZE] 00320 # NOTE USE OF THE "3 REF TRICK" # 00330 ; .WHILE (PTR .IS NOBODY ! .FALSE ! NAME .OF PTR /= NAME) 00340 .DO PTR := NEXTHASH .OF PTR .OD 00350 ; .IF PTR .IS NOBODY 00360 .THEN .REF .REF .PERSON (PTR) := .HEAP .PERSON := 00370 ( NAME, SEX, 0, .SKIP, NOBODY, NOBODY, NOBODY) 00380 .ELIF SEX .OF PTR = SEX .OR .NOT CHECK 00390 .THEN PTR 00400 .ELSE PRINT((NAME, " SEEMS TO HAVE CHANGED SEX", NEWLINE)) 00410 ; NOBODY 00420 .FI 00430 .FI 00440 ; .BEGIN # INPUT OF FAMILIES # 00450 .LOC .STRING FATHER, MOTHER, CHILD 00460 ; .LOC .REF .PERSON PA, MA, INFANT 00470 ; .LOC .CHAR SD # TO HOLD "S" FOR SON, OR "D" FOR DAUGHTER # 00480 ; .LOC .BOOL SEX # .TRUE FOR MALE # 00482 ; CLOSE(STANDIN) 00484 ; OPEN(STANDIN, "sisters", STAND IN CHANNEL) 00490 ; ON PAGE END(STAND IN, (.REF .FILE F).BOOL: (NEWPAGE(F); .GOTO RELATIONSHIP)) 00500 ; MAKE TERM(STAND IN, ",;.") 00510 ; RESTART: 00520 ( .PROC COMPLAIN = (.STRING MESSAGE).VOID: 00530 # IGNORES REMAINDER OF CURRENT LINE, AND RESTARTS INPUT LOOP # 00540 ( PRINT((MESSAGE, NEWLINE)) 00550 ; READ(NEWLINE) 00560 ; .GOTO RESTART 00570 ) 00580 ; .PROC EXPECT = (.CHAR E).VOID: 00590 # ABSORBS NEXT CHARACTER, COMPLAINING IF IT IS NOT AS EXPECTED # 00600 ( .LOC .CHAR C 00610 ; READ(C) 00620 ; .IF C/=E 00630 .THEN COMPLAIN(C+" FOUND INSTEAD OF "+E) 00640 .FI 00650 ) 00660 ; READ(FATHER); EXPECT(",") 00670 ; PA := HASHIN(FATHER, MALE, CHECK) 00680 ; READ(MOTHER); EXPECT(";") 00690 ; MA := HASHIN(MOTHER, FEMALE, CHECK) 00700 # IF FATHER(MOTHER) IS NOT SPECIFIED, 'NOBODY' GETS ASSIGNED TO PA(MA) # 00710 ; .IF (PA .IS NOBODY) .AND (MA .IS NOBODY) 00720 .THEN COMPLAIN("BOTH PARENTS MISSING") 00730 .FI 00740 ; .WHILE READ(SD) 00750 ; SEX := (SD="S" ! MALE !: SD="D" ! FEMALE ! COMPLAIN(SD+" FOUND INSTEAD OF S OR D"); .SKIP) 00760 ; EXPECT("=") 00770 ; READ(CHILD) 00780 ; INFANT := HASHIN(CHILD, SEX, CHECK) 00790 ; .IF INFANT .ISNT NOBODY 00800 .THEN .IF PA .OF INFANT .ISNT NOBODY 00810 .THEN COMPLAIN(CHILD+" ALREADY HAS A FATHER") 00820 .ELSE PA .OF INFANT := PA 00830 .FI 00840 ; .IF MA .OF INFANT .ISNT NOBODY 00850 .THEN COMPLAIN(CHILD+" ALREADY HAS A MOTHER") 00860 .ELSE MA .OF INFANT := MA 00870 .FI 00880 .ELSE COMPLAIN("CHILD'S NAME NOT GIVEN") 00890 .FI 00900 ; READ(SD) 00910 ; SD/="." 00920 .DO .SKIP .OD 00930 ; READ(NEWLINE) 00940 ; .GOTO RESTART 00950 ) 00960 .END # INPUT OF FAMILIES # 00970 ; RELATIONSHIP: 00980 .BEGIN # CHECKING OF RELATIONSHIPS # 00990 .LOC .STRING FIRST, SECOND 01000 ; .LOC .REF .PERSON THIS, THAT 01010 ; .MODE .CHAIN = .STRUCT(.INT UP, DOWN, .REF .CHAIN NEXT) 01020 ; .REF .CHAIN NOCHAIN = .NIL 01030 ; .LOC .REF .CHAIN START CHAIN 01040 ; .PROC INSERT CHAIN = (.INT UP, DOWN).VOID: 01050 ( .LOC .REF .CHAIN PTR := START CHAIN 01060 ; .WHILE (PTR :/=: NOCHAIN ! UP .OF PTR /= UP .OR DOWN .OF PTR /= DOWN ! .FALSE) 01070 .DO PTR := NEXT .OF PTR .OD 01080 ; .IF PTR :=: NOCHAIN .THEN START CHAIN := .HEAP .CHAIN := (UP, DOWN, START CHAIN) .FI 01090 ) 01100 ; .PROC RELATIONS = (.INT UP, DOWN).VOID: 01110 # PRINTS THE RELATIONSHIP BETWEEN 'THIS' AND 'THAT', ACCORDING TO 01120 'UP' AND 'DOWN' # 01130 PRINT((NAME .OF THIS 01140 , ( .PROC GREATS = (.INT N).STRING: N*"GREAT-" 01150 ; " IS THE " + 01160 .CASE UP+1 01170 .IN .CASE DOWN+1 01180 .IN "SAME AS " 01190 , (SEX .OF THIS ! "FATHER" ! "MOTHER") + " OF " 01200 .OUT GREATS(DOWN-UP-2) + "GRAND" + (SEX .OF THIS ! "FATHER" ! "MOTHER") + " OF " 01210 .ESAC 01220 , .CASE DOWN+1 01230 .IN (SEX .OF THIS ! "SON" ! "DAUGHTER") + " OF " 01240 , (SEX .OF THIS ! "BROTHER" ! "SISTER") + " OF " 01250 .OUT GREATS(DOWN-UP-1) + (SEX .OF THIS ! "UNCLE" ! "AUNT") + " OF " 01260 .ESAC 01270 .OUT .CASE DOWN+1 01280 .IN GREATS(UP-DOWN-2) + "GRAND" + (SEX .OF THIS ! "SON" ! "DAUGHTER") + " OF " 01290 , GREATS(UP-DOWN-1) + (SEX .OF THIS ! "NEPHEW" ! "NIECE") + " OF " 01300 .OUT .INT COUS = (UP