by James Thomas Lee, Jr. 12/25/97 Copyrighted 1995 by James Thomas Lee, Jr. Copyright Number: XXx xxx-xxx
Writing a program to read a program and then execute the instructions of that program was a fun and very challenging undertaking. In my technical and academic career, I have probably never had a greater experience, and concerning the learning benefits, this one must be right there at the top. Without the benefit of a guide or any kind of how-to-do-it manuals, this appendix shows how I determined to do it.
The first thing that one must understand is that my language and its special instructions were tasks that could be programmed. They followed the rules of logic, and they were predictable. For instance, if my Interpreter encountered an "IF ... THEN ..." instruction, it could examine the "IF" side of the expression, and if the condition were true, then it could evaluate the "THEN" side and take the appropriate action. If my Interpreter encountered a "GOTO" instruction, then it could transfer program control to the place in the program that was to be next executed. What I guess I am trying to say is that my Interpreter was very much like any other computer program. It read an input file and processed the data. The fact that the input file was an actual program to be itself executed was not an issue.
I had to figure out most of this program on my own, and so it was that, on my own, I determined that this interpreter had to be a two-pass process. I realized that if I was processing the input program and read a "GOTO" instruction that I would have to know where the transfer location was, even if that location was further down in the program. I also figured out that I did not want to have to continually re-parse every instruction to identify the instruction. So, I designed a first pass to my Interpreter, first to parse each instruction once and save it in an easily recognizable form, and second to identify all the declaration statements and all the labels.
For this important first part, I created a table in my Interpreter, called PERM. This table contained the rewritten form of the user's input program. For example, if the instruction was GOTO 100, the rewritten form for this instruction would be 'GO100. In front of each instruction, I put an apostrophe, followed by the first two letters of the instruction. Then, when the Interpreter later tried to execute the GOTO instruction, it knew that the first three chracters, 'GO, would be the instruction identifier. This simple notation made the whole process of executing the user's program much simpler.
For the second part of this first pass process, I had to capture all the declared variables and arrays and also retain program addresses for the labels. To do this, I created a table called TABLES. The first entry into TABLES was the data element name. The second entry was data type, such as IN for integer, RE for real, ST for string, and BO for boolean. If the data type was being used by an array, I also stored a relative array character address along with the data type. This address, which pointed to the place in PERM where the array's dimensioning information was stored, could be used during the second pass of the Interpreter for quick consideration of any dimensioning concerns. The third entry into TABLES showed the relative displacement of the particular variable in the data tables. This number would reflect the impact of arrays and also multiple word formats, such as real numbers which use two words. For example, if the first entry in TABLES was a ten-element integer array, the data table's pointer for this entry would be zero, because it is the first entry. For the next variable in TABLES, the displacement value would be ten because locations zero through nine would have been used by the integer array. If the second entry in TABLES was a real number, then the relative displacement for the third element would be ten plus two, or twelve, because each real number used two words. This fairly simple table arrangement made the locating of the user program's variables very quick and simple. For user program labels, such as for the aforementioned GOTO statement, the label would be listed in the first entry and the program address of the label would be contained in the third. The second entry was left zero because it was not needed.
The above two tables were the guts of my Interpreter. Other tables, however, were also used for various things. For string variables, which are of multiple word lengths, I maintained a table called STLGTAB (String Length Table). In this table, I simply showed the string variable name in the first entry and the length of the string in the second. Another table, called DATATAB, was where current data values were maintained during the second pass of the Interpreter. This information would actually be the data that was being processed by the user's input program.
Below are the equations that I used. Some of them, the first three, I derived myself, while others I got from a Calculus book.
a. Relative location of an array element = c(SUM(x(i)) * PROD(n(j))), where i=1 j=i+1 c => number of words of core for each array item d => dimensions of the array xi => the ith-parameter of the array, (i.e., a(i,j)) nj => the jth-parameter of the array, (i.e., a(i,j)) b. Converting from BCD (binary-coded decimal) to OCTAL (BCDOCTL). c. Converting from BCD to Floating Point (BCDFLPT). X**0 X**1 X**2 X**59 d. EXP (X) = ---- + ---- + ---- + . . . + ----- 0! 1! 2! 59! e. LN (X) = Y (I+1), where X-EXP(Y(I)) Y(I+1) = Y(I) + ----------------, and EXP(Y(I)) X > 0, Y(I+1) - Y(I) < .0000000001 f. LOG(X) = (2.302485093) * LN (X) g. SQRT (X) = Y(I+1), where X - Y(I)**2 Y(I+1) = Y(I) + ----------------, and 2 * Y(I) X > 0, Y(I+1) - Y(I) < .0000000001 h. FACT (X) = (X) * (X-1) * (X-2) * . . . * (1) X**1 X**3 X**5 X**7 X**9 X**11 i. SIN (X) = ---- - ---- + ---- - ---- + ---- - ----- 1! 3! 5! 7! 9! 11! X**0 X**2 X**4 X**6 X**8 X**10 j. COS (X) = ---- - ---- + ---- - ---- + ---- - ----- 0! 2! 4! 6! 8! 10! SIN(X) k. TAN (X) = ----------- COS(X) l. ASIN (X) = Y (I+1), where X-SIN(Y(I)) Y(I+1) = Y(I) + ----------------, and COS(Y(I)) 1 > X > -1, Y(I+1) - Y(I) < .0000000001 m. ACOS (X) = Y (I+1), where X-COS(Y(I)) Y(I+1) = Y(I) + ----------------, and SIN(Y(I)) 1 > X > -1, Y(I+1) - Y(I) < .0000000001 X**2 n. ATAN (X) = (ASIN ----------)**(1/2) (1 + X**2)
Send email to: tlee6040@aol.com