Turbo Pascal for DOS Tutorial by Glenn Grotzinger Part 20: Miscallaneous Topics copyright (c) by Glenn Grotzinger Hello. Here is a solution for the programming problem that was given in part 19 with a little background explanation. PART19A.PAS ----------- This was the program written to generate the binary data file for use with the actual word checker. A text file was written to facilitate reading in the data, one word per line, to ease implementation. program part19a; var infile: text; outfile: file; datastring: string[14]; begin assign(infile, 'SOMEWRDS.TXT'); assign(outfile, 'SOMEWRDS.DAT'); reset(infile); rewrite(outfile, 1); readln(infile, datastring); while not eof(infile) do begin blockwrite(outfile, datastring, sizeof(datastring)); writeln(datastring); readln(infile, datastring); end; blockwrite(outfile, datastring, sizeof(datastring)); writeln(datastring); close(infile); close(outfile); end. PART19B.PAS ----------- This is the actual word checker. It is made so the words typed into the keyboard do not have to be case sensitive with reference to the datafile. All prevalent errors have error-checking code. program part19b; type strtype = string[14]; nodeptr = ^node; node = record str: strtype; left, right: nodeptr; end; var tree: nodeptr; datastring: strtype; infile: file; procedure opendatafile(var infile: file; afile: string); begin assign(infile, afile); {$I-}reset(infile, 1);{$I+} if IOResult <> 0 then begin writeln('Terminating. ', afile, ' does not exist!'); halt(1); end; end; function upstr(instr: strtype):strtype; var i: byte; tempstr: strtype; begin tempstr := ''; for i := 1 to length(instr) do tempstr := tempstr + upcase(instr[i]); upstr := tempstr; end; procedure memoryerror; begin writeln('Out of memory.'); halt(1); end; procedure deletetree(var tree: nodeptr); begin if tree <> nil then begin deletetree(tree^.right); deletetree(tree^.left); dispose(tree); end; end; procedure inserttree(datastring: strtype; var tree: nodeptr); begin if tree = nil then begin if memavail - sizeof(tree) > 0 then new(tree) else memoryerror; tree^.str := datastring; tree^.left := nil; tree^.right := nil; end else begin if upstr(datastring) > tree^.str then inserttree(upstr(datastring), tree^.right); if upstr(datastring) < tree^.str then inserttree(upstr(datastring), tree^.left); end; end; procedure buildsearch(var infile: file; var tree: nodeptr); var datastring: strtype; begin blockread(infile, datastring, sizeof(datastring)); while not eof(infile) do begin inserttree(datastring, tree); blockread(infile, datastring, sizeof(datastring)); end; inserttree(datastring, tree); close(infile); end; procedure searchtree(datastring: strtype; tree: nodeptr); begin if tree = nil then writeln(datastring, ' was not found in the data file.') else begin if datastring = tree^.str then writeln(datastring, ' was found in the data file.') else begin if datastring > tree^.str then searchtree(datastring, tree^.right); if datastring < tree^.str then searchtree(datastring, tree^.left); end; end; end; procedure promptwrite; begin writeln('Type QUIT to terminate.'); writeln('Type a word, and we''ll see if it''s in the database.'); writeln; end; begin writeln('Database checker.'); writeln; opendatafile(infile, 'SOMEWRDS.DAT'); buildsearch(infile, tree); promptwrite; readln(datastring); while (upstr(datastring) <> 'QUIT') do begin searchtree(upstr(datastring), tree); promptwrite; readln(datastring); end; deletetree(tree); end. The written explanation of the delete code that was written in the example, to completely remove the BST from memory... We know that in a pointer-linked structure if we remove a node that has links assigned to it, that we will cause a heap leak and render the rest of the data structure unremovable from memory. In a BST, that case becomes when both right and left branches of the node are nil. We have to use recursion, evidently, since the problem of deleting the entire binary tree comes down to many smaller problems of deleting nodes with both sides assigned to nil, basically. So basically, if we observe those lines of code, recursion occurs until both the left and right sides of nodes become nil, and then a dispose occurs. In working back up in returning from the procedure calls, the tree is essentially disposed of from the bottom up to the root node, in reverse from the way the insert code illustration created it. Contents for Part 20 ==================== Since this part contains many random varied topics, a table of contents is in order.... A) Linking OBJ code into Pascal programs. B) Including ASM or inline statements in Pascal programs. C) Hooking an interrupt in pascal programs. D) Calling an interrupt procedure. E) Conditional Compiler Compilation. Linking OBJ code into Pascal programs ===================================== This is a short program, which describes the exact process, USING A C program's function (the topic of using C OBJ's came up). If you do this with C OBJ, the code must not make any calls to any C libraries, or make any calls to a DLL. A description of what's going on... TEST1.H int far pascal add2numbers(int num1, int num2) { return (num1 + num2); } This is a C header file with a small defined function in it. You MUST define it using either void far pascal for a procedure or far pascal for a function. I describe a function in test1.h. For those who wonder, a header file in C functions much like a unit does in Pascal. For an OBJ you intend to use, each and every function must be defined in the resultant pascal program. (I know it is not liked, and you SHOULD NEVER normally post attachments in c.l.p.b.) With differences between so many different C compilers and syntaxes that exist in the world, I will post the OBJ file I got from the compiler I use, for purposes of enabling others to test this. I recommend you to cut and paste it before you uu or xx encode it if you need to obtain it. begin 644 test1.obj M@`D`!U1%4U0Q+D..B!\````;5$,X-B!";W)L86YD(%1U boolean: indicates that the operating system is MS-DOS or PC-DOS CPU87 => boolean: true if there is a math coprocessor (FPU) present. The only construct you will typically see is an if then or if then else. The compiler directives I listed above are most commonly used with this type of situation. There are additional floating point data types available called comp, single, double, and extended; which are usable via the FPU generally. The definitions of these variables may be defined using the conditional compiler directives.... The conditional compiler directives we need to know are: {$IFDEF } If item defined {$IFNDEF } if item not defined {$ELSE} ELSE directive {$IFOPT } If compiler opt.. {$ENDIF} END IF STATEMENT {$DEFINE } define a statement {$UNDEF } undefine a statement. Functionally, these work and compile the source code if certain things are true. For example, {$IFOPT N+} {$ENDIF} in some code will make it so the code represented by will only be used if N+ is defined. Here is a short example program using conditional compiler directives.... program condcomptest; begin {$IFDEF CPU87} writeln('There is a math coprocessor in the system.'); {$ELSE} writeln('There is not a math coprocessor in the system.'); {$ENDIF} end. You will notice that only ONE writeln statement will execute itself. The dependence will be whether a FPU exists in your system. Practice Programming Problem #20 ================================ Write a program which will count the number of keystrokes a user presses in a period of 15 seconds. Use proper programming interest in this program, and be sure to be friendly to the user with this program. Background information. Keyboard interrupt is $09. Interrupt occurs 2 times for every key pressed. Notes: Unfortunately, in all attempts I've made, to make it TERMINATE exactly on 15 seconds, it would cause a nasty problem. The program will have to read in at least one key after termination. Do not worry about this. Next Time ========= We use the BGI. Write comments to ggrotz@2sprint.net.