{******************************************************** ** ** EDIT #5 - 12 July 1980 ** ** PROGRAM TITLE: Concordance ** ** WRITTEN BY: Raymond E. Penley ** DATE WRITTEN: 26 January 1980 ** ** WRITTEN FOR: Personal pleasure ** Donated to Pascal/Z users Gp ** ** PROGRAM SUMMARY: ** ** Examine a piece of text and produce a list, ** in alphabetical order, of all the distinct ** words which appear in the text. ** ** INPUT AND OUTPUT FILES: ** ** INPUT FILE: DRIVE: BASIC FILE NAME . EXTENSION ** OUT FILE: DRIVE: BASIC FILE NAME . CCD ** ************* } PROGRAM CONCORDANCE; label 9;{abort} const alfa_len = 16; { length of words } c4 = MAXINT;{ max line number } Clearcode = 26; { clear screen } default = 255; dflt_str_len = default; LLmax = default;{ max line length } LLmin = 72; { Min line length } space = ' '; StrMax = 255; type alfa = STRING alfa_len; byte = 0..255; charname = (lletter, uletter, digit, blank, quote, atab, EndOfLine, FileMark, otherchar ); charinfo = RECORD name : charname; valu : char END; dfltstr = STRING default;{ default length for all strings } ItemRecords = record item :alfa; Next :^ItemRecords end; ItemPointers = ^ItemRecords; str0 = string 0; str255 = string StrMax; var Look : char; { Character read in from File } cline : integer; { current line number } currchar, { Current operative character } nextchar : CharInfo; { Look-ahead character } CON_wanted, DEBUG, error_flag: BOOLEAN; Fbuffer : dfltstr; { Format buffer - before final Print } flushing : (KNOT, DBL, STD, LIT); ID : alfa; { Identifier storage } idlen : byte; { Identifier Length } ListHead :ItemPointers; tab : char; TextFile, { Input file } Work_File: TEXT; { Output file } wordcount: integer; { total # of words in file } xeof, { EOF status AFTER a read } xeoln : boolean; { EOLN status after a read } Function length(x: str255): integer; external; Procedure setlength(var x: str0; y: integer); external; Function index(x,y: str255): integer; external; PROCEDURE Error( enumb : byte); begin CASE enumb of 0: writeln('Fatal error!'); 1: writeln('Exceeded buffer limits on read'); 2: {-reserved-}; 3: writeln('File not found'); 4: {-reserved-} end{ of case }; error_flag := true end; PROCEDURE InsertItem( Newitem :alfa); {* ** From the book - PASCAL An Introduction ** to Methodical Programming ** Authors: ** W. Findlay and D.A. Watt ****** } VAR entry, PriorEntry, Newentry :ItemPointers; found :boolean; Procedure INSERTWORD; begin{ CREATE the New entry and Insert it in position } New(Newentry); Newentry^.item := Newitem; Newentry^.Next := entry; If entry = ListHead then ListHead := Newentry Else PriorEntry^.Next := Newentry; end{-of InsertWord-}; begin { FIND the position where the New item will be Inserted } entry := ListHead; found := false; While NOT found AND (entry <> NIL) do WITH entry^ DO If (item < Newitem) then begin PriorEntry := entry; entry := Next end Else found := true; If found then{-Crate a new entry in the list If necessary-} begin If (entry^.item <> Newitem) then InsertWord{ at position `entry` } end Else InsertWord{ at end of list } end{-of InsertItem-}; PROCEDURE WriteItems; CONST Sail = '*** INDEX ***'; var entry :ItemPointers; begin Writeln(Work_File, Sail); If CON_wanted then writeln(Sail); entry := ListHead; While entry <> NIL DO WITH entry^ DO begin Writeln(Work_File, item); If CON_wanted then writeln(item); entry := Next end end{--of WriteItems-}; Procedure ReadC(var nextchar : charinfo; var currchar : charinfo ); { revised 4 Jan 80, rep } begin{ Terminator status module. Stores terminator status "AFTER" a read. NOTE this play on words - after one char is actually "PRIOR TO" the next character } xeoln := EOLN(textfile); xeof := EOF(textfile); { read byte module } If NOT xeof then READ(Textfile, Look); { current operative character module } currchar := nextchar; With NextChar do begin{ Look-ahead character name module } If xeof then name := FileMark Else If xeoln then name := EndOfLine Else If LooK IN ['a'..'z'] then { lower case } name := lletter Else If LooK IN ['A'..'Z'] then { upper case } name := uletter Else If LooK IN ['0'..'9'] then { digit } name := digit Else If LooK = '''' then name := quote Else If LooK = TAB then name := atab Else If LooK = space then name := blank Else name := otherchar; CASE name of{ store character value module } EndOfLine, FileMark: Valu := space; Else: Valu := LooK end{ case name of }; End{ Look-ahead character name module }; end{ ReadC }; PROCEDURE GetL( var Fbuffer : dfltstr ); { ***** Get a line of text into users buffer. Flushes comment lines: Flushes lines of Literals: 'this is it' Ignores special characters & tabs: Recognizes End of File and End of Line. GLOBAL flushing : (KNOT, DBL, STD, LIT); Fbuffer = dfltstr LLmax = 0..Max Line length; ***** } var state : (scanning, terminal, overflow); begin { GetL } setlength(fbuffer,0); error_flag := false; state := scanning; REPEAT ReadC(Nextchar, Currchar); If (length(fbuffer) >= LLmax) then{ exceeded length of buffer } begin{ reset EOLN } state := overflow; READLN(fbuffer);{ reset EOLN } error(1) end Else begin If (currchar.name IN [FileMark,EndOfLine]) then state:=terminal{ end of line or end of file }; CASE flushing of KNOT: CASE currchar.name of lletter, uletter, digit, blank: begin{ store } append(fbuffer,currchar.valu); end; atab, quote, otherchar: begin{ Flush comments -convert tabs & other chars to spaces } If (currchar.valu='(') and (nextchar.valu='*') then flushing := DBL Else If (currchar.valu='{') then flushing := STD Else If currchar.name=quote then flushing := LIT; { convert to a space } append(fbuffer,space); end; else: { end of line -or- file mark } append(fbuffer,currchar.valu) end{ case currchar name of }; DBL: { scanning for a closing - double comment } If (currchar.valu ='*') and (nextchar.valu =')') then flushing := KNOT; STD: { scanning for a closing curley } If currchar.valu = '}' then flushing := KNOT; LIT: { scanning for a closing quote } If currchar.name = quote then flushing := KNOT end{ flushing case } end{ Else } UNTIL (state<>scanning); end{-of GetL-}; PROCEDURE ReadWord; { Analyze the Line into "words" } const space = ' '; var Cpos : byte; { Current Position pointer } begin{ ReadWord } Cpos := 1; { start at the beginning of a line } While (Cpos < length(fbuffer)) Do begin { skip spaces } while (Cpos < length(Fbuffer)) AND (fbuffer[Cpos]=space) Do Cpos:=Cpos+1; Setlength(ID,0);{ start with a null array } while (Cpos < length(fbuffer)) AND (fbuffer[Cpos ] <> space) Do begin{ accept only non-spaces } If (length(ID) '); readln(File_ID); If (length(File_ID)>fid_len) then setlength(File_ID,fid_len) Else PAD(File_ID, fid_len); RESET(File_ID, TextFile); If EOF(TextFile) then{ ABORT } begin error(3); ConnectFiles := false; end Else begin ix := index(File_ID,'.'); { search for an extension } jx := index(File_ID,' '); { search for the first space } If (ix=0) then{ no extension was specified } Setlength(File_ID,jx-1) Else Setlength(File_ID,ix-1); Setlength(New_ID,0); append(New_ID, File_ID); append(New_ID, dflt_extension); PAD(New_ID, fid_len); REWRITE(New_ID, Work_File); end; End{ of ConnectFiles }; Procedure Initialize; var ch: char; begin ListHead := NIL; { MAKE the LIST EMPTY } cline := 0; { current line counter } wordcount := 0; idlen := 0; tab := chr(9); { ASCII Tab character } flushing := KNOT{ flushing }; {-INITIALIZE look-ahead char-} nextchar.name := blank; nextchar.valu := space; writeln; WRITE('DEBUG?');READ(Ch); DEBUG := ((Ch='Y') or (Ch='y')); writeln; WRITE('Output to Console?');READ(Ch); CON_wanted := ((Ch='Y') or (Ch='y')); end; PROCEDURE Clear(code : byte); { device dependent routine } begin WRITELN( CHR(code) ) end; Procedure Sign_On; begin Clear(clearcode); writeln; writeln(' ':20,'*** C O N C O R D A N C E ***'); SKIP(4); end; Begin{ main body of Concordance } Sign_On; If NOT ConnectFiles then {ABORT} goto 9; Initialize; SKIP(4); cline:= cline +1; GetL(Fbuffer) { attempt to read the first line }; while ((currchar.name<>filemark) AND (NOT error_flag)) do begin {} If DEBUG then writeln('line',cline:5,' ',fbuffer); ReadWord{Analyze the Text into single 'words' }; If cline=c4 then cline:=0; cline := cline +1; GetL(Fbuffer) { attempt to read another line of text }; end{ while }; Clear(clearcode); WriteItems; { Write all the Items in order } writeln; writeln(' ':18, '*** SUMMARY ***'); writeln('Total # lines =',cline -1); writeln('Total # words =', wordcount); writeln; 9:{ABORT}; end{ of ConCordance }. .