, . . , STRCMP, SWAP; NUMCMP, - , STRCMP. MAIN SORT. SORT . , - . #DEFINE LINES 100 /* MAX NUMBER OF LINES TO BE SORTED */ MAIN(ARGC, ARGV) /* SORT INPUT LINES */ INT ARGC; CHAR *ARGV[]; \( CHAR *LINEPTR[LINES]; /* POINTERS TO TEXT LINES */ INT NLINES; /* NUMBER OF INPUT LINES READ */ INT STRCMP(), NUMCMP(); /* COMPARSION FUNCTIONS */ INT SWAP(); /* EXCHANGE FUNCTION */ INT NUMERIC = 0; /* 1 IF NUMERIC SORT */ IF(ARGC>1 && ARGV[1][0] == '-' && ARGV[1][1]=='N') NUMERIC = 1; IF(NLINES = READLINES(LINEPTR, LINES)) >= 0) \( IF (NUMERIC) SORT(LINEPTR, NLINES, NUMCMP, SWAP); ELSE SORT(LINEPTR, NLINES, STRCMP, SWAP); WRITELINES(LINEPTR, NLINES); \) ELSE PRINTF("INPUT TOO BIG TO SORT\N"); \) STRCMP, NIMCMP SWAP - ; - , , & , . . SORT: SORT(V, N, COMP, EXCH) /* SORT STRINGS V[0] ... V[N-1] */ CHAR *V[]; /* INTO INCREASING ORDER */ INT N; INT (*COMP)(), (*EXCH)(); \( INT GAP, I, J; FOR(GAP = N/2; GAP > 0; GAP /= 2) FOR(I = GAP; I < N; I++) FOR(J = I-GAP; J >= 0; J -= GAP) \( IF((*COMP)(V[J], V[J+GAP]) <= 0) BREAK; (*EXCH)(&V[J], &V[J+GAP]); \) \) - . INT (*COMP)() , COMP , INT. ; INT *COMP() , COMP , - , , , . COMP IF (*COMP)(V[J], V[J+GAP]) <= 0) : COMP - - , *COMP - , (*COMP)(V[J], V[J+GAP]) - . . STRCMP, : NUMCMP(S1, S2) /* COMPARE S1 AND S2 NUMERICALLY */ CHAR *S1, *S2; \( DOUBLE ATOF(), V1, V2; V1 = ATOF(S1); V2 = ATOF(S2); IF(V1 < V2) RETURN(-1); ELSE IF(V1 > V2) RETURN(1); ELSE RETURN (0); \) SWAP, . , - , . SWAP(PX, PY) /* INTERCHANGE *PX AND *PY */ CHAR *PX[], *PY[]; \( CHAR *TEMP; TEMP = *PX; *PX = *PY; *PY = TEMP; \) , - : .  5-11 --------------- SORT , -R, () . , -R -N.  5-12 --------------- -F, , : - , '' '' , - .  5-13 --------------- -D (" - "), , . , - -F.  5-14 --------------- , . - - . ( - -DF -N ).  * 6. *  - , , . ( , , ""). - : "" - , , , (...), , - , .. - : ... - , , . , , , , . , . - , , , , . 6.1.  5. , , , , , , . : STRUCT DATE \( INT DAY; INT MONTH; INT YEAR; INT YEARDAY; CHAR MON_NAME[4]; \); , , STRUCT. STRUCT , - ( DAT). . , , - . , (.. ), - . , . , - , , , . STRUCT \( ...\) X,Y,Z; INT X,Y,Z; , X , Y Z - . , - , - ; - . , , - - . , DATE, STRUCT DATE D; D DATE. , : STRUCT DATE D=\( 4, 7, 1776, 186, "JUL"\); - . -------------------- "." - . LEAP ( ) , D, LEAP = D.YEAR % 4 == 0 && D.YEAR % 100 != 0 \!\! D.YEAR % 400 == 0; IF (STRCMP(D.MON_NAME, "AUG") == 0) ... , D.MON_NAME[0] = LOWER(D.MON_NAME[0]); ; - : STRUCT PERSON \( CHAR NAME[NAMESIZE]; CHAR ADDRESS[ADRSIZE]; LONG ZIPCODE; /* */ LONG SS_NUMBER; /* . */ DOUBLE SALARY; /* */ STRUCT DATE BIRTHDATE; /* */ STRUCT DATE HIREDATE; /* */ \); PERSON DATE . EMP STRUCT PERSON EMP; EMP.BIRTHDATE.MONTH . "." . 6.2.  "C" . , - , - , & . , , . ( ). - , . , , - , ; - . , , . - , , . DAY_OF_YEAR, 5: D.YEARDAY = DAY_OF_YEAR(D.YEAR, D.MONTH, D.DAY); . HIREDATE STRUCT DATE HIREDATE; DAY_OF_YEAR , - HIREDATE YEARDAY = DAY_OF_YEAR(&HIREDATE); HIREDATE DAY_OF_YEAR . - , - , . DAY_OF_YEAR(PD) /* SET DAY OF YEAR FROM MONTH, DAY */ STRUCT DATE *PD; \( INT I, DAY, LEAP; DAY = PD->DAY; LEAP = PD->YEAR % 4 == 0 && PD->YEAR % 100 != 0 \!\! PD->YEAR % 400 == 0; FOR (I =1; I < PD->MONTH; I++) DAY += DAY_TAB[LEAP][I]; RETURN(DAY); \) STRUCT DATE *PD; , PD DATE. , PD->YEAR . P - , P-> ------------------ . ( -> - - , ">".) PD , YEAR (*PD).YEAR , - -> . (*PD).YEAR , , * . , "->" ".", - , P->Q->MEMB (P->Q)->MEMB EMP.BIRTHDATE.MONTH (EMP.BIRTHDATE).MONTH , MONTH_DAY, - . MONTH_DAY(PD) /* SET MONTH AND DAY FROM DAY OF YEAR */ STRUCT DATE *PD; \( INT I, LEAP; LEAP = PD->YEAR % 4 == 0 && PD->YEAR % 100 != 0 \!\! PD->YEAR % 400 == 0; PD->DAY = PD->YEARDAY; FOR (I = 1; PD->DAY > DAY_TAB[LEAP][I]; I++) PD->DAY -= DAY_TAB[LEAP][I]; PD->MONTH = I; \) "->" "." () [] , , - . , , STRUCT \( INT X; INT *Y; \) *P; ++P->X , , ++(P->). : (++P)-> P - , (P++)->X P . ( . ?) *P->Y , - Y; *P->Y++ Y , ( , *S++); (*P->Y)++ - , Y; *P++->Y P - , Y. 6.3.  . , , - "C". - . - KEYWORD KEYCOUNT: CHAR *KEYWORD [NKEYS]; INT KEYCOUNT [NKEYS]; , , - . - : CHAR *KEYWORD; INT KEYCOUNT; , , . STRUCT KEY \( CHAR *KEYWORD; INT KEYCOUNT; \) KEYTAB [NKEYS]; KEYTAB . . : STRUCT KEY \( CHAR *KEYWORD; INT KEYCOUNT; \); STRUCT KEY KEYTAB [NKEYS]; KEYTAB , . - - - : STRUCT KEY \( CHAR *KEYWORD; INT KEYCOUNT; \) KEYTAB[] =\( "BREAK", 0, "CASE", 0, "CHAR", 0, "CONTINUE", 0, "DEFAULT", 0, /* ... */ "UNSIGNED", 0, "WHILE", 0 \); . "" : \( "BREAK", 0 \), \( "CASE", 0 \), . . . , - . , - KEYTAB, - , [] . - KEYTAB. - , GETWORD, - . KEYTAB , 3. (, - , ). #DEFINE MAXWORD 20 MAIN() /* COUNT "C" KEYWORDS */ \( INT N, T; CHAR WORD[MAXWORD]; WHILE ((T = GETWORD(WORD,MAXWORD)) != EOF) IF (T == LETTER) IF((N = BINARY(WORD,KEYTAB,NKEYS)) >= 0) KEYTAB[N].KEYCOUNT++; FOR (N =0; N < NKEYS; N++) IF (KEYTAB[N].KEYCOUNT > 0) PRINTF("%4D %S\N", KEYTAB[N].KEYCOUNT, KEYTAB[N].KEYWORD); \) BINARY(WORD, TAB, N) /* FIND WORD IN TAB[0]...TAB[N-1] */ CHAR *WORD; STRUCT KEY TAB[]; INT N; \( INT LOW, HIGH, MID, COND; LOW = 0; HIGH = N - 1; WHILE (LOW <= HIGH) \( MID = (LOW+HIGH) / 2; IF((COND = STRCMP(WORD, TAB[MID].KEYWORD)) < 0) HIGH = MID - 1; ELSE IF (COND > 0) LOW = MID + 1; ELSE RETURN (MID); \) RETURN(-1); \) GETWORD; , LETTER , , . NKEYS - KEYTAB . , , , . - KEYTAB, . , , . SIZE OF KEYTAB / SIZE OF STRUCT KEY , "C" SIZEOF, , . SIZEOF(OBJECT) , . ( - , "- ", , CHAR). , , , INT DOUBLE, , . , - . #DEFINE NKEYS: #DEFINE NKEYS (SIZEOF(KEYTAB) / SIZEOF(STRUCT KEY)) GETWORD. - GETWORD, , . GETWORD "" , , , - . - ; - LETTER, , EOF , . GETWORD(W, LIM) /* GET NEXT WORD FROM INPUT */ CHAR *W; INT LIM; \( INT C, T; IF (TYPE(C=*W++=GETCH()) !=LETTER) \( *W='\0'; RETURN(C); \) WHILE (--LIM > 0) \( T = TYPE(C = *W++ = GETCH()); IF (T ! = LETTER && T ! = DIGIT) \( UNGETCH(C); BREAK; \) \) *(W-1) - '\0'; RETURN(LETTER); \) GETWORD GETCH UNGETCH, 4: - , GETWORD . - UNGETCH . GETWORD TYPE - . - , ASCII. TYPE(C) /* RETURN TYPE OF ASCII CHARACTER */ INT C; \( IF (C>= 'A' && C<= 'Z' \!\! C>= 'A' && C<= 'Z') RETURN(LETTER); ELSE IF (C>= '0' && C<= '9') RETURN(DIGIT); ELSE RETURN(C); \) LETTER DIGIT , , -, EOF; #DEFINE LETTER 'A' #DEFINE DIGIT '0' GETWORD , TYPE TYPE[ ]. "C" - ISALPHA ISDIGIT, .  6-1 -------------- GETWORD , .  6-2 -------------- TYPE, - .  6-3 -------------- , - - . 6.4.  , , , , . KEYTAB , MAIN BINARY . MAIN() /* COUNT C KEYWORD; POINTER VERSION */ \( INT T; CHAR WORD[MAXWORD]; STRUCT KEY *BINARY(), *P; WHILE ((T = GETWORD(WORD, MAXWORD;) !=EOF) IF (T==LETTER) IF ((P=BINARY(WORD,KEYTAB,NKEYS)) !=NULL) P->KEYCOUNT++; FOR (P=KEYTAB; P>KEYTAB + NKEYS; P++) IF (P->KEYCOUNT > 0) PRINTF("%4D %S/N", P->KEYCOUNT, P->KEYWORD); \) STRUCT KEY *BINARY(WORD, TAB, N) /* FIND WORD */ CHAR *WORD /* IN TAB[0]...TAB[N-1] */ STRUCT KEY TAB []; INT N; \( INT COND; STRUCT KEY *LOW = &TAB[0]; STRUCT KEY *HIGH = &TAB[N-1]; STRUCT KEY *MID; WHILE (LOW <= HIGH) \( MID = LOW + (HIGH-LOW) / 2; IF ((COND = STRCMP(WORD, MID->KEYWORD)) < 0) HIGH = MID - 1; ELSE IF (COND > 0) LOW = MID + 1; ELSE RETURN(MID); \) RETURN(NULL); \) , - . -, BINARI , KEY, ; MAIN, BINARY. BINARI , - ; , NULL. -, KEYTAB - . - BINARY: MID = (LOW + HIGH) / 2 - ( 2) - . MID = LOW + (HIGH-LOW) / 2 MID , LOW HIGH. LOW HIGH. - ; . MAIN FOR (P=KEYTAB; P < KEYTAB + NKEYS; P++) P , P , P++ P , P - . , , - - "". , , - . , , , STRUCT KEY *BINARY(WORD, TAB, N) T , . - : STRUCT KEY * BINARY(WORD, TAB, N) ; , , . 6.5. ,  , - , - . , . - , - , ; . ( , ). , ? , , - . O , , - . , - . "" ; : ---------------------- ----------------------- ----------------------------- ------------------------------ ; - . , - , , , - . , , , - . , . , ; . - , - , . , . - . , , : STRUCT TNODE \( /* THE BASIC NODE */ CHAR *WORD; /* POINTS TO THE TEXT */ INT COUNT; /* NUMBER OF OCCURRENCES */ STRUCT TNODE *LEFT; /* LEFT CHILD */ STRUCT TNODE *RIGHT; /* RIGHT CHILD */ \); "" - , . , STRUCT TNODE *LEFT; LEFT , . , , , , . GETWORD ALLOC . - GETWORD , TREE. #DEFINE MAXWORD 20 MAIN() /* WORD FREGUENCY COUNT */ \( STRUCT TNODE *ROOT, *TREE(); CHAR WORD[MAXWORD]; INT T; ROOT = NULL; WHILE ((T = GETWORD(WORD, MAXWORD)) \! = EOF) IF (T == LETTER) ROOT = TREE(ROOT, WORD); TREEPRINT(ROOT); \) TREE . - MAIN () . , - , TREE , . - , ( ), , - - . TREE - , - . STRUCT TNODE *TREE(P, W) /* INSTALL W AT OR BELOW P */ STRUCT TNODE *P; CHAR *W; \( STRUCT TNODE *TALLOC(); CHAR *STRSAVE(); INT COND; IF (P == NULL) \( /* A NEW WORD HAS ARRIVED */ P == TALLOC(); /* MAKE A NEW NODE */ P->WORD = STRSAVE(W); P->COUNT = 1; P->LEFT = P->RIGHT = NULL; \) ELSE IF ((COND = STRCMP(W, P->WORD)) == 0) P->COUNT++; /* REPEATED WORD */ ELSE IF (COND < 0)/* LOWER GOES INTO LEFT SUBTREE */ P->LEFT = TREE(P->LEFT, W); ELSE /* GREATER INTO RIGHT SUBTREE */ P->RIGHT = TREE(P->RIGHT, W); RETURN(P); \) TALLOC, - ALLOC, - . - , . ( ). - STRSAVE , - , . . STRSAVE TALLOC ( - ). TREEPRINT , - ; ( , ), , ( , ). , TREEPRINT ; , . TREEPRINT (P) /* PRINT TREE P RECURSIVELY */ STRUCT TNODE *P; \( IF (P != NULL) \( TREEPRINT (P->LEFT); PRINTF("%4D %S\N", P->COUNT, P->WORD); TREEPRINT (P->RIGHT); \) \) : "- " - , - , . , - , - . - , 2-3 AVL , " ", . , - . , , . CHAR - STRUCT TNODE, . - : , (, - )? : - , , ALLOC ? , , , , . , PDP-11 , ALLOC , . - . . , ALLOC , - . ALLOC 5 ; 8 , . ALLOC , - . "C" - , ALLOC - CHAR, - . , P CHAR *P; (STRUCT TNODE *) P TNODE . , TALLOC : STRUCT TNODE *TALLOC() \( CHAR *ALLOC(); RETURN ((STRUCT TNODE *) ALLOC(SIZEOF(STRUCT TNODE))); \) , - .  6-4 ---------------- , "C"- - , - , - . ( , 7 ).  6-5 ---------------- , .. , , - .  6-6 ---------------- , , - . - . 6.6.  - , - . - - . , , #DEFINE "C". #DEFINE YES 1 YES 1 . - , YES INWORD = YES; O 1. , - . INSTALL(S,T) - S T ; S T . LOOKUP(S) S , , NULL, . - - , - . , , . - , NULL. , , . . STRUCT NLIST \( /* BASIC TABLE ENTRY */ CHAR *NAME; CHAR *DEF; STRUCT NLIST *NEXT; /* NEXT ENTRY IN CHAIN */ \); DEFINE HASHSIZE 100 TATIC STRUCT NLIST *HASHTAB[HASHSIZE] /* POINTER TABLE */ , - LOOKUP INSTALL , . ( , ). HASH(S) /* FORM HASH VALUE FOR STRING */ CHAR *S; \( INT HASHVAL; FOR (HASHVAL = 0; *S != '\0'; ) HASHVAL += *S++; RETURN(HASHVAL % HASHSIZE); \) - HASHTAB ; - , , - . LOOKUP. LOOKUP , , ; , NULL. STRUCT NLIST *LOOKUP(S) /* LOOK FOR S IN HASHTAB */ CHAR *S; \( STRUCT NLIST *NP; FOR (NP = HASHTAB[HASH(S)]; NP != NULL;NP=NP->NEXT) IF (STRCMP(S, NP->NAME) == 0) RETURN(NP); /* FOUND IT */ RETURN(NULL); /* NOT FOUND */ INSTALL LOOKUP - , ; , . . - , INSTALL NULL. STRUCT NLIST *INSTALL(NAME, DEF) /* PUT (NAME, DEF) */ CHAR *NAME, *DEF; \( STRUCT NLIST *NP, *LOOKUP(); CHAR *STRSAVE(), *ALLOC(); INT HASHVAL; IF((NP = LOOKUP(NAME)) == NULL) \( /* NOT FOUND */ NP = (STRUCT NLIST *) ALLOC(SIZEOF(*NP)); IF (NP == NULL) RETURN(NULL); IF ((NP->NAME = STRSAVE(NAME)) == NULL) RETURN(NULL); HASHVAL = HASH(NP->NAME); NP->NEXT = HASHTAB[HASHVAL]; HASHTAB[HASHVAL] = NP; \) ELSE /* ALREADY THERE */ FREE((NP->DEF);/* FREE PREVIOUS DEFINITION */ IF ((NP->DEF = STRSAVE(DEF)) == NULL) RETURN (NULL); RETURN(NP); \) STRSAVE , - , , ALLOC. - 5. ALLOC FREE - , ALLOC 5 - ; 7 8.  6-7 --------------- , - , LOOKUP INSTALL.  6-8 --------------- , - , #DEFINE , "C"-. GETCHAR UNGETCH. 6.7.  - , ; - - , . - , - - . , . , , , / .. - - - CHAR INT. , , - "", - , #DEFINE KEYWORD 01 #DEFINE EXTERNAL 02 #DEFINE STATIC 04 ( ). " " , , 2. : FLAGS \!= EXTERNAL \! STATIC; EXTERNAL STATIC FLAGS, FLAGS &= \^(XTERNAL \! STATIC); , IF ((FLAGS & (EXTERNAL \! STATIC)) == 0) ... , . , "C" , - . - INT. . , - #DEFINE, , : STRUCT \( UNSIGNED IS_KEYWORD : 1; UNSIGNED IS_EXTERN : 1; UNSIGNED IS_STATIC : 1; \) FLAGS; FLAGS, - 1- . . UNSIGNED, - , . , FLAGS.IS_STATIE, FLAGS. IS_EXTERN, FLAGS.IS_KEYWORD .., , . - , . - , : FLAGS.IS_EXTERN = FLAGS.IS_STATIC = 1; ; FLAGS.IS_EXTERN = FLAGS.IS_STATIC = 0; ; IF (FLAGS.IS_EXTERN == 0 &&FLAGS.IS_STATIC == 0)... . INT; , , - INT. ; ( ) - . INT,