Home of the original IBM PC emulator for browsers.
[PCjs Machine "ibm5160"]
Waiting for machine "ibm5160" to load....
This is the second issue of PC Firing Line, with the magazine's official
title. It has been positioned as the underground newspaper for the IBM
user. You will be presented with the untold tales and in-depth
programming aids. Some of the articles are ADA, Assembly routines,
LISP, Fortran, and items not written about by IBM. It also contains
many sample program listings with accompanying documentation.
Special Requirements: None.
How to Start: Type GO (press enter).
Suggested Registration: $12.00
File Descriptions:
??? TXT Various information and reviews (22 files).
ADABOOK REV Book reviews on 6 different ADA books.
GRABBAG C Source code for USQ.C.
ITOP LSP Routine converts infix to prefix mathematical expressions.
LISP1 TXT Various mathematical utilities.
LIST1 ADA Various mathematical utilities
LIST1 ASM Various mathematical utilities.
LIST1 BAS Various mathematical utilities
LIST1 C Various mathematical utilities
LIST1 FOR Various mathematical utilities.
PCFL EXE PC-Firing Line main program.
PRETTY1 COM Printer interface routine.
READISCO PE Documentation for READISCOPE program.
SPLITA BAT Splits this diskette for side sided copying.
WRITERS GDE Text file.
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ The Ada Tutorial - Part I ║
║ ║
║ by ║
║ ║
║ George Gordon Noel ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Introduction │
└──────────────────────────────────┘
In the last issue we looked at Ada through a wide-angle
lens, examining the history and key features of the
language. It is time to zoom-in for a closer look. This
article is the first in a series of Ada tutorials, and if
you follow along closely, and practice what you learn with
an "Ada compiler," before long you will be writing Ada
programs. By the time this series concludes, you will be
privy to some of the most advanced programming concepts in
the history of computers.
┌──────────────────────────────────┐
│ The Program AVERAGE │
└──────────────────────────────────┘
If you are not firmly grounded in the basics of Ada,
the more esoteric parts of the language (and there are lots
of them) will leave you bewildered. Therefore, this first
installment is devoted to the simple, rock-bottom details
that appear in every Ada program. We investigate some of
these details through a program that finds the average of
two integers.
with TEXT_IO; use TEXT_IO;
procedure AVERAGE is
package INT_IO is new TEXT_IO.INTEGER_IO (integer);
use INT_IO;
FIRST_NUMBER: integer;
SECOND_NUMBER: integer;
AVG: integer;
begin
put ("Enter a number: ");
NEW_LINE;
get (FIRST_NUMBER);
put ("And another number: ");
NEW_LINE;
get (SECOND_NUMBER);
AVG := (FIRST_NUMBER + SECOND_NUMBER) / 2;
put ("The average is: ");
NEW_LINE;
put (AVG);
end AVERAGE;
This program prompts the user for a number, reads an
integer from the standard input device into the variable
FIRST_NUMBER, repeats this process for SECOND_NUMBER, sums,
divides, and places the result in the variable AVG, which is
printed along with a final message.
Aside from the curious first, third, and fourth lines
of this program, you might think that we are working in
Pascal or some other familiar language. We won't examine
the details of these three lines until later in this series,
except to say that any program that performs input/output
operations involving integer numbers, must contain these
three lines of code.
Now, let's examine the features of this program that
are similar to features in existing, better known languages.
Our AVERAGE program is an example of a "procedure," a
program unit familiar from PL/1 and other languages. A
procedure is a convenient way of grouping together data and
commands for implementing some specific job.
┌──────────────────────────────────┐
│ The Declaritive Portion │
└──────────────────────────────────┘
AVERAGE is divided into a "declarative part," which is
the first indented region of the program, and a series of
statements in the second indented region. (According to the
formal rules of Ada, there are actually four distinct
sections in this program. We won't be meeting the remaining
two for quite some time.)
The declarative part is where you establish the
existence of data objects (and other items, as we will see),
and will be covered in my next installment. For now, just
observe that the last three lines in the declarative part
create three integer variables.
The statements grouped between the words begin and end
are commands that implement the code of AVERAGE. The get
statement receives information from the standard input
device (presumably a keyboard), and the put statement
transmits information to the standard output device
(presumably a display screen.)
┌──────────────────────────────────┐
│ NEW_LINE and := │
└──────────────────────────────────┘
The NEW_LINE command sends a carriage return and line
feed to the screen.
The final kind of statement in this example is the
familiar assignment statement in line 15. The assignment
operator is the := symbol, which Ada shares with Pascal,
Algol, and Modula II.
┌──────────────────────────────────┐
│ Use of Semicolons │
└──────────────────────────────────┘
Notice that most lines in the example end in
semicolons. The use of semicolons is more consistent in Ada
than in Pascal. Semicolons "terminate" statements in Ada
rather than "separate" them as in Pascal. Semicolons only
come after statements and declarations. The word begin is
not a statement, nor is the second line (called the
"procedure specification") that ends with the word is. The
program as a whole ends with a semicolon rather than a
period, as it would in Pascal.
In our example program, the procedure name, AVERAGE, is
repeated before the final semicolon. This is not required,
but it is almost universal practice among Ada programmers.
┌──────────────────────────────────┐
│ Reserved Words │
└──────────────────────────────────┘
Like many other languages, Ada has "reserved words" or
"keywords" that have a fixed meaning which the programmer
can not modify. In the examples in this article, reserved
words appear in lower case to distinguish them from the
"user defined identifiers," or symbols created by the
programmer, which are in upper case. (The I/O procedures
get and put are library routines, as in C, meaning that the
words get and put are not reserved. They occur so often,
however, that programmers usually write them in lower case
to avoid constantly banging the shift key.) If you attempt
to redefine a keyword - for instance, if you tried to
declare an integer variable called "procedure" - an error
message would be issued.
Keywords, however, may be imbedded in larger
identifiers. This means that you could have an integer
variable called DOLLARS even though the word "do" is a
keyword in Ada.
┌──────────────────────────────────┐
│ Identifiers │
└──────────────────────────────────┘
Ada identifiers can consist of letters of the alphabet,
numbers, and the underscore character. You can make them as
long as you like (indeed, Ada identifiers tend to be wordy)
but they must start with a letter. X2 is a legal Ada
identifier but 2X is not. Use underscore characters for
readability, but remember they can not be the first or last
character in an identifier, and they can not appear
consecutively. FIRST_NUMBER and TEXT_IO are fine but _OUCH,
WRONG_, and OH___MY are illegal. Also, Ada does not
distinguish between upper and lower case; the identifiers
Harold, HAROLD, harold, and hArOlD are identical in Ada. We
will, however, use the convention of writing all user
defined identifiers in upper case.
Aside from identifiers, the most common symbols in an
Ada program are numbers and punctuation. Let's look at
numbers.
┌──────────────────────────────────┐
│ Ada Data Types │
└──────────────────────────────────┘
One of the most imposing things about Ada is the huge
number of data types. Although other languages have integer
and floating-point numbers, characters, and Boolean
(true/false) data types, Ada goes all out with a vast
supermarket of data types, both ordinary and exotic. (Ada
is sometimes criticized as a "kitchen sink" language that
attempts to be all things to all people.) Since data types
will be the topic of my next two columns, we only briefly
look at numbers now, mostly just to see how they are
written.
Like other languages, numbers in Ada are divided into
two categories - integers, or whole numbers, and reals, or
numbers with a fractional part. You can distinguish between
them because reals have a decimal point and integers don't,
just like in FORTRAN.
0, 12, -99, 32767 -- integers
0.0, 3.14, -0.025 -- reals
Both kinds of numbers can be preceded by a minus sign
to indicate that the number is negative or by an optional
plus sign if it is positive. Multi-digit numbers of both
varieties can be made easier to read by using the underscore
character; the number 1000000 is the same as the number
1_000_000.
┌──────────────────────────────────┐
│ Based Numbers │
└──────────────────────────────────┘
Ada allows you to write numbers in bases other than ten
by using a special "based number" notation. The base of the
number system is written, followed by a # symbol, the number
in question, and another #. For example, 8#32# is a number
in base 8 which equals (3 * 8) + (2 * 1) or 26 in base 10.
The number 2#1010# is a binary (base 2) number equal to 10
in decimal. Ada lets you use any number system from base 2
to base 16. In bases 11 through 16, Ada employs the
"superdigits" A, B, C, D, E, and F to represent the numbers
10 through 15. For instance, the based number 16#1A# equals
(1 * 16) + (10 * 1), or 26 in base 10.
Based numbers are mostly used in programs that interact
very closely with the underlying hardware. This means that
the number systems commonly associated with computers -
binary, octal (base 8), and hexadecimal (base 16) - will be
used most often.
┌──────────────────────────────────┐
│ Arithmetic Operators │
└──────────────────────────────────┘
Ada has a number of "operators" for performing
calculations: The arithmetic operators, +, -, *, and /, are
the same as in other languages. There is also a ** operator
for exponentiation, an abs operator for taking the absolute
value of a number, a rem operator for computing the
remainder after division, and a mod operator for modular
arithmetic.
2 ** 3 -- equals 8
abs -60 -- equals 60
12 mod -5 -- equals -3
12 rem -5 -- equals 2
The differences between the mod and rem operators are
too subtle to explain here. If you are interested, see the
Ada Language Reference Manual or ALM (reviewed in this issue
of PCFL/PCUG.)
Like other languages, numeric expressions can be
arbitrarily complicated, and can include variables like
FIRST_NUMBER and numeric "literals" like 5 or 29.7.
Expressions are evaluated according to the precedence of the
operators, which is similar to other languages, and
parentheses may be used to change the order of evaluation.
┌──────────────────────────────────┐
│ Ada's Strong Typing │
└──────────────────────────────────┘
Numeric expressions should only involve one kind of
number - integers should be kept with integers and reals
with reals. This is because Ada is a "strongly typed"
language, or one that does not allow mixing of data types.
(In this respect, Ada is like Pascal and unlike C, FORTRAN,
and PL/1.) Thus, it is acceptable to write 1 + 2, but (1 +
2.0) is not acceptable because an integer and a real number
are mixed.
Strong typing has effects throughout Ada. You must be
certain that the data type of the expression on the
right-hand side of an assignment statement matches the data
type of the target variable on the left side:
AVG := 2; -- okay since AVG is an integer
AVG := 2.0; -- gives an error message
As another example, the NEW_LINE command appearing in
our first example program may be supplied with an optional
"parameter," in parentheses, to indicate how many blank
lines are to be printed. The statement NEW_LINE prints one
blank line, while NEW_LINE(3) prints three blank lines.
Since it would be meaningless to print a fractional number
of blank lines, NEW_LINE expects an integer parameter.
┌──────────────────────────────────┐
│ Relaxing Strong Typing │
└──────────────────────────────────┘
It is not always possible to live by Ada's strict rules
regarding data types. On occasion, you may not be able to
avoid adding integers and real numbers. To help out in
these times of need, Ada has limited facilities for "type
conversion" - changing a value of one type to another type.
This is done by writing the value to be converted in
parentheses, preceded by the name of the desired type. The
following statement converts a floating-point number to type
integer, adds the new integer value to two other integers,
and assigns the result to an integer variable.
AVG := AVG + 15 + integer (30.9);
The effect of type conversion, along with other
features of numbers in Ada, is demonstrated in the next
example.
procedure PLAY_WITH_NUMBERS is
X: integer;
begin
-- the first two statements in this program
-- demonstrate how different numeric notations
-- can be combined in one expression
X := 10000 + 10_000; -- X equals 20000
X := 5 + 8#24#; -- X equals 25
-- the next statement demonstrates integer division
X := 5 / 2; -- X equals 2
-- now let's see some type conversion
X := 2 * integer (2.7); -- X equals 6
end PLAY_WITH_NUMBERS;
First, notice that this program does not do any
input/output. The lack of I/O eliminates the need for the
TEXT_IO facilities that made the last program look so
mysterious.
This program also includes comments. Recall that
comments begin with a double dash and extend to the end of
the line. A comment must either occupy an entire line or
come at the end of the line.
The first two assignments show that Ada does not care
how integer numbers are written - you can mix ordinary
integers with based numbers and numbers including the
underscore character.
The third assignment demonstrates that if the quotient
of two integers is not an integer, Ada lops off the
fractional part to produce an integer result.
The opposite happens with type conversion. When you
change a real number to an integer, Ada rounds up or down,
as indicated. The expression "integer (1.1)" equals 1 while
"integer (1.7)" equals 2.
┌──────────────────────────────────┐
│ Conclusions │
└──────────────────────────────────┘
The parts of Ada that we met in this installment were
not flashy or even that different from other, more familiar
languages. They are, however, important building blocks
that will act as a foundation for our coming work. The
flashier parts of Ada will start appearing in the next issue
when we begin our discussion of data types. (A more complex
example - the famous Byte magazine prime number benchmark -
appears in the "Ada Programs" section of this column.)
As always, your questions about Ada and critical
comments on these articles are welcome. Send them to the
author care of PCFL/PCUG.
┌──────────────────────────────────┐
│ File Name: ██ ada1.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ Introduction to Assembly Language ║
║ ║
║ by ║
║ ║
║ Bill Salkin ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Introduction │
└──────────────────────────────────┘
This month's column discusses BIOS and DOS routines,
and introduces the DEBUG program.
┌──────────────────────────────────┐
│ DOS Function Calls │
└──────────────────────────────────┘
DOS function calls are similar to subroutine calls in
other languages, and perform many useful services such as:
display a string on the screen, accept input from the
keyboard, perform file I/O, delete files, rename files,
determine the time and date stamp on a file, read the
directory of a disk, and others.
In FORTRAN, the subroutine SUB is invoked by the
statement "CALL SUB", and the code in this subroutine is
then executed. DOS function calls are invoked by the
statement "INT 21H" (interrupt 21 hex), but INT 21H is a
subroutine with many entry points (entrances). It has
numerous options, with each option corresponding to a
different function or service. For example, the program
DISPLAY, presented in last month's sample program section,
displays a string on the screen by using service #9:
MOV AH,9 ;REQUEST "PRINT STRING" SERVICE
MOV DX,OFFSET STRINGY ;DX HAS THE ADDRESS OF STRINGY
INT 21H ;INVOKE "PRINT STRING" SERVICE
The service number is placed in the AH register, and
INT 21H is invoked to begin execution of the requested
service.
DOS function calls (often referred to as "INT 21H"
calls) are listed in the appendix "DOS Interrupts and
Function Calls" of the DOS manual. Study that section and
familiarize yourself with the many services that are
available. In particular, verify that #9 is the proper
value for printing a string. You may not understand the
explanations, but note how the statement of service #9 was
translated and used in DISPLAY.
Think: DOS function call = INT 21H
┌──────────────────────────────────┐
│ BIOS Calls │
└──────────────────────────────────┘
The BIOS is a collection of important services that
deal directly with the hardware, such as the 6845 CRT
controller. The BIOS is stored on a ROM chip in the PC.
Some BIOS services that programmers can access are:
┌──────────────────────────────────────────────────┐
│ │
│ 1. equipment determination (how many disk │
│ drives are attached to the system?, is a │
│ color monitor present?,etc.) │
│ │
│ 2. read characters from the keyboard │
│ │
│ 3. handle printer interfacing │
│ │
│ 4. handle asynchronous communications │
│ │
│ 5. scroll "windows" on the screen (used to │
│ clear the screen) │
│ │
│ 6. determine the amount of RAM in the PC. │
│ │
└──────────────────────────────────────────────────┘
The source code of the BIOS is included in the IBM
Technical Reference Manual, and should probably not be read
by beginning programmers. Later though, it will prove
invaluable.
In the routine CLEAR, also presented in last month's
sample program section, the screen is cleared by using the
"scroll screen" service #6. Like a DOS function call, the
service number is moved into the AH register:
MOV AH,6 ;REQUEST "SCROLL SCREEN" SERVICE
INT 10H ;INVOKE "SCROLL SCREEN" SERVICE
The actual operation that clears the screen is invoked
by INT 10H. You will not find this interrupt listed in the
DOS manual, for it is a BIOS call. It is found in the BIOS
listing in the Technical Reference Manual, under the heading
"Display (VIDEO) I/O." INT 10H is the BIOS call for general
screen handling and can be used to change the cursor size,
print characters at the cursor position, set medium or high
resolution mode, create windows that are smaller than the
display screen, and a variety of other functions.
Unlike DOS, which centralizes all services under INT
21H, each of the many BIOS services (screen, diskette, etc.)
has its own interrupt number. Screen I/O uses INT 10H,
while diskette I/O uses INT 13H. Each BIOS service has many
sub-services.
It may be a pleasant pastime for some to leisurely read
the BIOS and extract the information it contains, but this
work has already been done. The BIOS calls are presented in
any decent assembly language book, and were also presented
in the first issue of PCFL/PCUG. (See "The Interrupt
PhoneBook," in the DOS column.) So, you need not purchase
the Technical Reference Manual to obtain a copy of these
calls, but it is to your advantage to own this manual. When
you gain experience in assembly language, it will prove a
valuable reference - you will be amazed at the information
omitted from available texts.
┌──────────────────────────────────┐
│ Comparison of BIOS and DOS Calls │
└──────────────────────────────────┘
In many respects, BIOS and DOS calls are complementary,
each addressing deficiencies in the other. It is necessary
to master the fundamentals of using both types of calls if
you wish to use your PC to its fullest advantage.
BIOS calls perform "utility" type services, and are not
truly a part of PC-DOS operating system. Portability of
programs, to other MS-DOS machines, may be compromised by
using BIOS calls.
Programs employing only standard DOS calls are
guaranteed a large degree of portability and should run on
other computers using DOS.
Many programmers, the "good" guys, insist that BIOS
calls should not be used - only DOS calls should be used.
Other programmers, the "bad" guys, use the BIOS and do nasty
tricks that hamper program portability. This is generally
done because a desired function is not available through
DOS. (Incidentally, DOS 2.0 has rectified many of the
omissions that forced programmers to use BIOS services under
DOS 1.1, instead of DOS services.)
In truth, I am one of the "bad" guys - but, for good
reasons. BIOS and DOS calls are relatively slow, and faster
screen response (among other items) can be obtained by
writing custom-tailored routines that duplicate BIOS and DOS
functions. (The main-menu handler for PCFL/PCUG avoids some
of the available BIOS and DOS calls, to increase the speed
of the panel display.)
┌──────────────────────────────────┐
│ DEBUG │
└──────────────────────────────────┘
New topic time! Focus on DEBUG.
DEBUG is not used only to debug programs. It can be
used to understand how instructions actually work when the
reference manual is unclear, or to view memory, or to
single-step through your program and check for errors.
DEBUG provides a controlled environment in which assembly
code can be tested.
The routine DISPLAY is used as our introduction to
DEBUG.
;COPYRIGHT 1984 BY ABComputing
;
; ┌───────────────────────────────────────────────────────────────────┐
; │ │
; │ THIS ROUTINE DISPLAYS THE STRING "I have the world on a │
; │ string", AND RETURNS TO DOS. │
; │ │
; │ PLACE THIS ROUTINE IN FILE : DISPLAY.ASM │
; │ │
; └───────────────────────────────────────────────────────────────────┘
;
;------------------------------------------------------------------------
DATA SEGMENT PARA
STRINGY DB 'I have the world on a string','$'
DATA ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
STACK SEGMENT PARA STACK 'STACK'
DB 40H DUP('STCK')
STACK ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
CODE SEGMENT PARA
ASSUME CS:CODE, DS:DATA, SS:STACK
;--STANDARD LINKAGE TO DOS
DISPLAY PROC FAR ;DO
PUSH DS ;
SUB AX,AX ;
PUSH AX ; NOT
MOV AX,DATA ;
MOV DS,AX ; ALTER!
;--PRINT THE STRING "STRINGY"
MOV AH,9 ;REQUEST "PRINT STRING" SERVICE
MOV DX,OFFSET STRINGY ;DX HAS THE ADDRESS OF STRINGY
INT 21H ;INVOKE "PRINT STRING" SERVICE
;-- RETURN TO DOS
RET ;RETurn to DOS
DISPLAY ENDP ;END of Procedure
CODE ENDS ;END of code Segment
;------------------------------------------------------------------------
END DISPLAY ;END of routine DISPLAY
Assuming you have assembled and linked this program,
the executable module is in the file DISPLAY.EXE.
I will use drive D, which contains the routines
CLEAR.EXE, DISPLAY.EXE, and the DEBUG program (DEBUG.EXE),
for the remainder of this article.
To invoke DEBUG, type DEBUG after the DOS prompt,
followed by the name of the executable module to be
"debugged," and press the ENTER key. This loads DEBUG and
the module into memory, and DEBUG displays its prompt, a
minus sign (-).
Type "U" for Unassemble and DEBUG will decode the
contents of the module, and present an assembly-like
listing.
D>DEBUG DISPLAY.EXE
-U
098E:0000 1E PUSH DS
098E:0001 2BC0 SUB AX,AX
098E:0003 50 PUSH AX
098E:0004 B89009 MOV AX,0990
098E:0007 8ED8 MOV DS,AX
098E:0009 B409 MOV AH,09
098E:000B BA0000 MOV DX,0000
098E:000E CD21 INT 21
098E:0010 CB RETF <──── End of routine DISPLAY
098E:0011 0000 ADD [BX+SI],AL
098E:0013 0000 ADD [BX+SI],AL
098E:0015 0000 ADD [BX+SI],AL
098E:0017 0000 ADD [BX+SI],AL
098E:0019 0000 ADD [BX+SI],AL
098E:001B 0000 ADD [BX+SI],AL
098E:001D 0000 ADD [BX+SI],AL
098E:001F 004920 ADD [BX+DI+20],CL
Only the code segment of DISPLAY is shown, but notice
how compressed it is in contrast to the code segment in the
source file! The unassembled version does not contain
comments (as the assembler removes them), and labels in the
source code, such as DATA and STRINGY, have been replaced by
numbers (addresses). DISPLAY ends with the RETF statement
shown above, but DEBUG obligingly unassembles "code" beyond
the end of our program (which is of no value to us.)
A sample line from the unassembly is interpreted as
follows:
address machine lang assembler equivalent
098E:0000 1E PUSH DS
We will not be concerned with the meaning of the
address field yet, or the machine language equivalent of the
instruction. Notice that "PUSH DS" in the unassembly is the
first statement in the code segment of the original source
code.
Let's single-step or walk-through our program. Typing
"T" for trace yields:
-T
AX=0000 BX=0000 CX=0180 DX=0000 SP=00FE BP=0000 SI=0000 DI=0000
DS=097E ES=097E SS=0992 CS=098E IP=0001 NV UP DI PL NZ NA PO NC
098E:0001 2BC0 SUB AX,AX
This is the second instruction in our program! We are
getting warmer. The "T" command traced, or completed, the
first instruction, and DEBUG displays the next instruction
to be executed.
The contents of all registers are displayed on two
lines, and the instruction to be executed on the bottom
line. We have not discussed many of these registers, but at
this time you should recognize AX, BX, CX, and DX. The AX,
BX, and DX registers contain a hex 0, while CX contains 180
hex = 384 decimal.
Typing "T" will execute the instruction listed above;
we are executing our program one instruction at a time.
-T
AX=0000 BX=0000 CX=0180 DX=0000 SP=00FE BP=0000 SI=0000 DI=0000
DS=097E ES=097E SS=0992 CS=098E IP=0003 NV UP DI PL ZR NA PE NC
098E:0003 50 PUSH AX
-T ┌──┐
AX=0000 BX=0000 CX=0180 DX=0000 SP=00FC BP=0000 SI=0000 DI=0000
DS=097E ES=097E SS=0992 CS=098E IP=0004 NV UP DI PL ZR NA PE NC
098E:0004 B89009 MOV AX,0990
└┬─┘
┌───────────────────────────────┘
│
│ AX contains zero before this instruction is executed,
│ and will contain 990 after it is executed.
│
-T ┌┴─┐
AX=0990 BX=0000 CX=0180 DX=0000 SP=00FC BP=0000 SI=0000 DI=0000
DS=097E ES=097E SS=0992 CS=098E IP=0007 NV UP DI PL ZR NA PE NC
W98E:0007 8ED8 MOV DS,AX
Recall from my first column, the DS is a pointer to the
data segment. DISPLAY's data segment consists of the string
"I have the world on a string." We verify this by "dumping"
the contents of the data segment using the "D" or dump
command. To dump the data segment from its start type:
-D DS:0000
0990:0000 49 20 68 61 76 65 20 74-68 65 20 77 6F 72 6C 64 I have the world
0990:0010 20 6F 6E 20 61 20 73 74-72 69 6E 67 24 00 00 00 on a string$...
0990:0020 53 54 43 4B 53 54 43 4B-53 54 43 4B 53 54 43 4B STCKSTCKSTCKSTCK
0990:0030 53 54 43 4B 53 54 43 4B-53 54 43 4B 53 54 43 4B STCKSTCKSTCKSTCK
0990:0040 53 54 43 4B 53 54 43 4B-53 54 43 4B 53 54 43 4B STCKSTCKSTCKSTCK
0990:0050 53 54 43 4B 53 54 43 4B-53 54 43 4B 53 54 43 4B STCKSTCKSTCKSTCK
0990:0060 53 54 43 4B 53 54 43 4B-53 54 43 4B 53 54 43 4B STCKSTCKSTCKSTCK
0990:0070 53 54 43 4B 53 54 43 4B-53 54 43 4B 53 54 43 4B STCKSTCKSTCKSTCK
There's our string and the "STCK" pattern in the far
right side of the display. If you study the source code for
DISPLAY, you will note that the stack segment immediately
follows the data segment, and this is precisely what DEBUG
shows us. DEBUG gives one a good feel for the relationship
of various segments in a program.
Attentive readers will note that while the stack
segment immediately follows the data segment in the source
code, there are three periods separating the $ from the word
STCK in the DEBUG display. We will discuss this in a later
column under "segment alignment."
-T
AX=0990 BX=0000 CX=0180 DX=0000 SP=00FC BP=0000 SI=0000 DI=0000
DS=0990 ES=097E SS=0992 CS=098E IP=0009 NV UP DI PL ZR NA PE NC
098E:0009 B409 MOV AH,09
The number 9 is moved into the AH register to indicate
the "print string" service.
-T
AX=0990 BX=0000 CX=0180 DX=0000 SP=00FC BP=0000 SI=0000 DI=0000
DS=0990 ES=097E SS=0992 CS=098E IP=000B NV UP DI PL ZR NA PE NC
098E:000B BA0000 MOV DX,0000
DX has the address of the string to be printed, as
measured relative to the start of the data segment. Moving
0 into DX means that our string has an "offset" of 0 bytes
into the data segment. That is, the first byte of our
string starts at the beginning of the data segment.
Finally typing "G" for Go will cause the program to be
executed. The "Program terminated normally" message was
issued by DEBUG; it is not part of DISPLAY.
-G
I have the world on a string
Program terminated normally
To exit DEBUG and return to DOS, type "Q", for quit.
-Q
D>
-------------------------------------------------------------------
;COPYRIGHT 1984 BY ABComputing
;
; ┌───────────────────────────────────────────────────────────────────┐
; │ │
; │ THIS ROUTINE CLEARS THE SCREEN BY MAKING A BIOS CALL. │
; │ │
; │ PLACE THIS ROUTINE IN FILE : CLEAR.ASM │
; │ │
; └───────────────────────────────────────────────────────────────────┘
;
;------------------------------------------------------------------------
DATA SEGMENT PARA
DATA ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
STACK SEGMENT PARA STACK 'STACK'
DB 40H DUP('STCK')
STACK ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
CODE SEGMENT PARA
ASSUME CS:CODE, DS:DATA, SS:STACK
;--STANDARD LINKAGE TO DOS
CLEAR PROC FAR ;DO
PUSH DS ;
SUB AX,AX ;
PUSH AX ; NOT
MOV AX,DATA ;
MOV DS,AX ; ALTER!
;--NOTE 24 DECIMAL = 18H, AND 79 DECIMAL = 4FH
MOV AH,6 ;REQUEST SCROLL SCREEN SERVICE
MOV AL,0 ;SCROLL ENTIRE WINDOW
MOV BH,7 ;WHITE FOREGROUND, BLACK BACKGROUND
MOV CX,0000H ;UPPER LEFT CORNER (0,0)
MOV DX,184FH ;LOWER RIGHT (24,79)
INT 10H ;INVOKE SCROLL SCREEN SERVICE
;-- RETURN TO DOS
RET ;RETurn to DOS
CLEAR ENDP ;END of Procedure
CODE ENDS ;END of code Segment
;------------------------------------------------------------------------
END CLEAR ;END of routine CLEAR
D>DEBUG CLEAR.EXE
-U
098E:0000 1E PUSH DS
098E:0001 2BC0 SUB AX,AX
098E:0003 50 PUSH AX
098E:0004 B89009 MOV AX,0990
098E:0007 8ED8 MOV DS,AX
098E:0009 B406 MOV AH,06
098E:000B B000 MOV AL,00
098E:000D B707 MOV BH,07
098E:000F B90000 MOV CX,0000
098E:0012 BA4F18 MOV DX,184F
098E:0015 CD10 INT 10
098E:0017 CB RETF <──── End of routine CLEAR
098E:0018 0000 ADD [BX+SI],AL
098E:001A 0000 ADD [BX+SI],AL
098E:001C 0000 ADD [BX+SI],AL
098E:001E 0000 ADD [BX+SI],AL
-T
AX=0000 BX=0000 CX=0180 DX=0000 SP=00FE BP=0000 SI=0000 DI=0000
DS=097E ES=097E SS=0990 CS=098E IP=0001 NV UP DI PL NZ NA PO NC
098E:0001 2BC0 SUB AX,AX
-T
AX=0000 BX=0000 CX=0180 DX=0000 SP=00FE BP=0000 SI=0000 DI=0000
DS=097E ES=097E SS=0990 CS=098E IP=0003 NV UP DI PL ZR NA PE NC
098E:0003 50 PUSH AX
-T
AX=0000 BX=0000 CX=0180 DX=0000 SP=00FC BP=0000 SI=0000 DI=0000
DS=097E ES=097E SS=0990 CS=098E IP=0004 NV UP DI PL ZR NA PE NC
098E:0004 B89009 MOV AX,0990
-t
AX=0990 BX=0000 CX=0180 DX=0000 SP=00FC BP=0000 SI=0000 DI=0000
DS=097E ES=097E SS=0990 CS=098E IP=0007 NV UP DI PL ZR NA PE NC
098E:0007 8ED8 MOV DS,AX
-T
┌┐
AX=0990 BX=0000 CX=0180 DX=0000 SP=00FC BP=0000 SI=0000 DI=0000
DS=0990 ES=097E SS=0990 CS=098E IP=0009 NV UP DI PL ZR NA PE NC
098E:0009 B406 MOV AH,06
└┘
┌────────────────────────┘
│
│ AH, which is the upper byte of the AX register,
│ contains "09" before this instruction is executed, and will
│ contain "06" after it is executed.
│
-T ┌┐
AX=0690 BX=0000 CX=0180 DX=0000 SP=00FC BP=0000 SI=0000 DI=0000
DS=0990 ES=097E SS=0990 CS=098E IP=000B NV UP DI PL ZR NA PE NC
098E:000B B000 MOV AL,00
└┬┘
┌──────────────────────────────┘
┌┐
AX=0600 BX=0000 CX=0180 DX=0000 SP=00FC BP=0000 SI=0000 DI=0000
DS=0990 ES=097E SS=0990 CS=098E IP=000D NV UP DI PL ZR NA PE NC
098E:000D B707 MOV BH,07
-T
BH contains "00", and will contain "07" after this
instruction is executed.
┌┐
AX=0600 BX=0700 CX=0180 DX=0000 SP=00FC BP=0000 SI=0000 DI=0000
DS=0990 ES=097E SS=0990 CS=098E IP=000F NV UP DI PL ZR NA PE NC
098E:000F B90000 MOV CX,0000
-T
┌──┐
AX=0600 BX=0700 CX=0000 DX=0000 SP=00FC BP=0000 SI=0000 DI=0000
DS=0990 ES=097E SS=0990 CS=098E IP=0012 NV UP DI PL ZR NA PE NC
098E:0012 BA4F18 MOV DX,184F
-G
Program terminated normally
-Q
What can not be shown is that the screen cleared after
the "G" command was typed.
┌──────────────────────────────────┐
│ Conclusion │
└──────────────────────────────────┘
We covered a lot of information this time. Study the
DOS function calls, BIOS calls, and experiment. Try
DEBUGging any programs you write.
Next month, we will discuss BIOS/DOS calls further, and
I hope to introduce the topic of subroutine calls.
┌──────────────────────────────────┐
│ File Name: ██ asm1.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ DOS 1.1, 2.0 Sequential File-Reading ║
║ ║
║ by ║
║ ║
║ Bill Salkin ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Introduction │
└──────────────────────────────────┘
This article discusses sequential file-reading under
DOS 1.1 and DOS 2.0. The source code given performs the
following functions: read one byte from the file
"A:JUNK.TXT", display it, and continue in this manner until
an end-of-file (EOF) condition is reached.
DOS 2.0 uses a new approach to file handling that was
not available under DOS 1.1. For this reason, separate
source code and commentary are provided for each release.
┌──────────────────────────────────┐
│ FCB vs. ASCIIZ │
└──────────────────────────────────┘
In DOS 1.1, the liaison or "link" between the physical
file as stored on the disk, and the file as viewed by the
programmer, is called the file control block (FCB).
An FCB is a 37-byte data structure containing
file-related information such as: the filespec, time and
date stamp, the file size, current block, and record size.
The FCB map or layout of a "standard" FCB is shown
below:
0 ┌────────┬─────────────────────────────────────────────────────────┐
│ Drive │ Filename (8 bytes) │
8 ├────────┼─────────────────────────┬─────────────────┬─────────────┤
│ │ File extension │ Current Block │ Record Size │
16 ├────────┴───────┬─────────────────┼─────────────────┼─────────────┤
│File size (low) │File size (high) │ Date │▓▓▓▓▓▓▓▓▓▓▓▓▓│
24 ├────────────────┴─────────────────┴─────────────────┘▓▓▓▓▓▓▓▓▓▓▓▓▓│
│▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ Reserved for system use ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓│
32 ├────────┬───────────────┬─────────────────┬───────────────────────┘
│Current │ Random Record │ Random Record │
│Record │ # (low) │ # (high) │
└────────┴───────────────┴─────────────────┘
As offset 0 from the start of the FCB is the drive
specifier for the file. (Other fields are discussed later.)
A file is associated with an FCB by the filename and file
extension fields of the FCB. When we speak of "opening" a
file, we actually are opening the FCB associated with this
file. This abuse of terms is enjoyed by all writers, and I
will be equally loose.
DOS 2.0 offers an improved approach to file handling by
using ASCIIZ strings. This approach is easier to program,
more flexible, and more uniform than methods employing FCBs.
Furthermore, FCBs need not be used under DOS 2.0, as new
file-handling routines have been introduced to perform the
functions of earlier FCB-bound ones.
┌──────────────────────────────────┐
│ DOS 1.1 File-handling │
└──────────────────────────────────┘
┌──────────────────┐
│ FCB Structure │
└──────────────────┘
Program 1, shown later in this file, establishes an FCB
for file "A:JUNK.TXT" in our data segment, by the statement:
FCB DB 1,'JUNK ','TXT',25 DUP(0)
An FCB is called unopened when it contains only the
drive specifier and filespec. The FCB given above is an
unopened FCB.
The "1" shown is a drive specifier meaning the file is
on the "A" drive (2 = "B" drive, 3 = "C" drive, etc.)
Blanks were added after the filename "JUNK" to account for
an eight-character filename. The file extension is "TXT,"
and the remainder of the FCB is padded with zeroes.
┌──────────────────┐
│ Setting the DTA │
└──────────────────┘
Data read from a disk is stored in an area called the
Disk Transfer Area (DTA). In Program 1, we instruct DOS to
set the DTA location to an area we can access easily. We
select IO_AREA (a one-byte buffer in our data segment) as
the DTA by using DOS function call 1AH, with DS:DX pointing
to the area that we want for our DTA (IO_AREA).
MOV AH,1AH ;REQUEST "SET DTA" SERVICE
MOV DX,OFFSET IO_AREA ;SET DTA TO IO_AREA
INT 21H ;INVOKE "SET DTA" SERVICE
The DTA will remain at IO_AREA until the DTA address is
reset by another 1AH function call.
┌──────────────────┐
│ Opening an FCB │
└──────────────────┘
After the DTA has been set to IO_AREA, the FCB (for
file "A:JUNK.TXT") is opened. This is required before any
read (or write) operation can occur.
DOS call 0FH opens the FCB corresponding to the file
"A:JUNK.TXT".
MOV AH,0FH ;REQUEST "OPEN FCB" SERVICE
MOV DX,OFFSET FCB ;MAKE DS:DX -> FCB
INT 21H ;INVOKE "OPEN FCB" SERVICE
┌──────────────────┐
│ FCB Fields │
└──────────────────┘
DOS's logical view of a file is a collection of
"blocks," with each block consisting of 128 "records." The
current block and current record fields of an FCB (offsets
12 and 32 bytes from the FCB start) are used during
sequential read/write operations as pointers to the next
record to read/write. Setting the current block and record
number fields to zero, positions the read/write pointer to
the beginning of the file. This is accomplished as follows:
MOV WORD PTR FCB+12,0 ;SET CURRENT BLOCK NUMBER TO 0
MOV FCB+32, 0 ;SET CURRENT RECORD TO 0
With the read/write pointer at the start of the file,
we next specify the amount of data to be read with each read
operation. This amount is given by the value in the record
size field (at offset 14 bytes from FCB start) which we
change to a "1" as we want to read one byte. (This one-byte
length is referred to as RECORD_LENGTH in Program 1.) The
code performing this is:
MOV WORD PTR FCB+14,RECORD_LENGTH
The sequential-read operation automatically updates the
current block and record fields, positioning the read/write
pointer for the next read operation.
┌──────────────────┐
│ Reading the File │
└──────────────────┘
DOS call 14H is used to perform the sequential read,
with DS:DX pointing to the open FCB for the file to be read.
But as DS:DX already points to the desired FCB (from the
open service), to read one byte into IO_AREA, we use:
MOV AH,14H ;REQUEST "READ FILE" SERVICE
INT 21H ;INVOKE "READ FILE" SERVICE
The value returned in AL is not zero if an EOF
condition was encountered. We continue reading and
displaying one byte, until the EOF marker is reached. When
the EOF marker is encountered, the FCB is closed using DOS
call 10H, and the program terminates.
MOV AH,10H ;REQUEST "CLOSE FILE" SERVICE
INT 21H ;INVOKE "CLOSE FILE" SERVICE
┌──────────────────┐
│ Program 1 │
└──────────────────┘
;COPYRIGHT 1984 BY ABComputing
;
; ┌───────────────────────────────────────────────────────────────────┐
; │ │
; │ THIS PROGRAM READS AND DISPLAYS THE FILE "A:JUNK.TXT" ONE │
; │ BYTE AT A TIME. ONLY DOS 1.1 FUNCTION CALLS ARE USED. │
; │ │
; │ THIS FILE IS ASSUMED TO EXIST, AND NO CHECK IS MADE FOR │
; │ THIS. │
; │ │
; └───────────────────────────────────────────────────────────────────┘
;
;------------------------------------------------------------------------------
MAIN_DATA SEGMENT PARA PUBLIC 'DATA'
RECORD_LENGTH EQU 1 ;LENGTH OF RECORD READ INTO DTA
FCB DB 1,'JUNK ','TXT',25 DUP(0)
IO_AREA DB RECORD_LENGTH DUP(0),'$' ;"IN-ROOM" FOR DISK READS
MAIN_DATA ENDS
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
STACK SEGMENT PARA STACK 'STACK'
DB 40H DUP('STCK')
STACK ENDS
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
CODE SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CODE,DS:MAIN_DATA,SS:STACK,ES:NOTHING
MAIN PROC FAR ;STANDARD LINKAGE TO DOS
PUSH DS ; DO
MOV AX,0 ;
PUSH AX ; NOT
MOV AX,MAIN_DATA ;
MOV DS,AX ; ALTER!
CALL READ_FILE ;READ AND DISPLAY THE FILE
RET
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
;ROUTINE READ_FILE
;
; BRIEF:
; READS THE FILE "A:JUNK.TXT" AND DISPLAYS IT ON THE SCREEN.
;
; INPUT:
; RECORD_LENGTH: THE NUMBER OF BYTES TO READ FROM THE FILE
; WITH EACH READ OPERATION.
;
; AN FCB FOR THE FILE "A:JUNK.TXT"
;
; AN INPUT DATA AREA (IO_AREA) WHERE EACH RECORD READ FROM THE
; FILE IS BUFFERED.
;
; OUTPUT:
; THE FILE "A:JUNK.TXT" IS DISPLAYED ON THE SCREEN.
;
;------------------------------------------------------------------------------
READ_FILE PROC NEAR
PUSH AX
PUSH DX
;--PERFORM ALL DISK TRANSFERS TO IO_AREA
MOV AH,1AH ;REQUEST "SET DTA" SERVICE
MOV DX,OFFSET IO_AREA ;SET DTA TO IO_AREA
INT 21H ;INVOKE "SET DTA" SERVICE
;--OPEN FCB FOR FILE
MOV AH,0FH ;REQUEST "OPEN FCB" SERVICE
MOV DX,OFFSET FCB ;MAKE DS:DX -> FCB
INT 21H ;INVOKE "OPEN FCB" SERVICE
;--ADJUST FCB TO READ "RECORD_LENGTH" BYTES, STARTING AT BEGINNING OF FILE
MOV WORD PTR FCB+12,0 ;SET CURRENT BLOCK NUMBER TO 0
MOV WORD PTR FCB+14,RECORD_LENGTH
MOV FCB+32, 0 ;SET CURRENT RECORD TO 0
;--READ "RECORD_LENGTH" BYTES INTO IO_AREA (RECALL DS:DX -> FCB)
REA1: MOV AH,14H ;REQUEST "READ FILE" SERVICE
INT 21H ;INVOKE "READ FILE" SERVICE
CMP AL,0 ;AL = 0 IF READ WAS FINE
JNE REA2 ;AL <> 0 IF EOF
;--WRITE "IO_AREA" TO SCREEN
PUSH DX ;SAVE DX FOR FILE READ
MOV AH,9 ;REQUEST "PRINT STRING" SERVICE
MOV DX,OFFSET IO_AREA
INT 21H ;INVOKE "PRINT STRING" SERVICE
POP DX ;RESTORE DX FOR FILE READ.
JMP REA1 ;GET NEXT BYTE
;--CLOSE FCB (RECALL DS:DX -> FCB)
REA2: MOV AH,10H ;REQUEST "CLOSE FILE" SERVICE
INT 21H ;INVOKE "CLOSE FILE" SERVICE
POP DX
POP AX
RET
READ_FILE ENDP
;------------------------------------------------------------------------------
MAIN ENDP ;END of MAIN procedure
CODE ENDS ;END of CODE Segment
END MAIN ;END of assembly.
┌──────────────────────────────────┐
│ DOS 2.0 File-handling │
└──────────────────────────────────┘
Program 2, shown below, uses DOS 2.0 function calls to
read the file "A:JUNK.TXT". (The same file read by Program
1.)
The FCB concept in DOS 2.0 has been replaced by the
simpler ASCIIZ string approach. An ASCIIZ string is a
string containing the path (optional) and filespec,
terminated by a byte of zeroes. An example is:
FILE DB 'A:JUNK.TXT',0
Notice that the filespec is typed; the filename and
extension are not separate fields as in the FCB approach,
nor is the filename blank padded to occupy 8 characters.
ASCIIZ strings are easier to use than FCBs and provide a
level of insulation from the file-management structure that
was not possible under DOS 1.1.
┌──────────────────┐
│ Opening the File │
└──────────────────┘
A file is opened under DOS 2.0 using one of three
access methods. Each access method has an access code, and
we use access code 0 to open the file for reading only.
(The other access methods allow writing only, or both
reading and writing.)
When the file specified in the ASCIIZ string is opened,
a word pointer, called a handle, is associated with it, and
this handle is used whenever we wish to perform any
operation with the file.
Opening a file under DOS 2.0 automatically points the
read/write pointer to the first byte of the file and sets
the record size to one byte. How convenient; this is
exactly the set up we need to read one byte from a file!
It seems quite involved to open a file. At least the
explanation is; the required code is simpler to write than
it is to explain.
;--OPEN THE FILE "A:JUNK.TXT" FOR READING ONLY.
MOV AH,3DH ;REQUEST "OPEN FILE" SERVICE
MOV AL,0 ;FILE OPENED FOR READING
MOV DX,OFFSET FILE ;DS:DX -> FILE TO BE READ
INT 21H ;INVOKE "OPEN FILE" SERVICE
┌──────────────────┐
│ Reading the File │
└──────────────────┘
To read the file we invoke DOS function call 3FH, with
the file handle in BX, the buffer address in DS:DX, and the
number of bytes to read in CX. The number of bytes actually
read is returned in AX. If AX = 0, then the EOF marker was
read. This one call combines the functions of many DOS 1.1
calls.
After the file has been read and displayed, the file
handle associated with the file is closed. This closes the
file, and the program terminates.
┌──────────────────┐
│ Program 2 │
└──────────────────┘
;COPYRIGHT 1984 BY ABComputing
;
; ┌───────────────────────────────────────────────────────────────────┐
; │ │
; │ THIS PROGRAM READS AND DISPLAYS THE FILE "A:JUNK.TXT" ONE │
; │ BYTE AT A TIME. ONLY DOS 2.0 FUNCTION CALLS ARE USED. │
; │ │
; │ THIS FILE IS ASSUMED TO EXIST, AND NO CHECK IS MADE FOR │
; │ THIS. │
; │ │
; └───────────────────────────────────────────────────────────────────┘
;
;------------------------------------------------------------------------------
MAIN_DATA SEGMENT PARA PUBLIC 'DATA'
RECORD_LENGTH EQU 1 ;NUMBER OF BYTES TO READ.
FILE DB 'A:JUNK.TXT',0
IO_AREA DB RECORD_LENGTH DUP(0),'$' ;"IN-ROOM" FOR DISK READS
MAIN_DATA ENDS
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
STACK SEGMENT PARA STACK 'STACK'
DB 40H DUP('STCK')
STACK ENDS
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
CODE SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CODE,DS:MAIN_DATA,SS:STACK,ES:NOTHING
MAIN PROC FAR ;STANDARD LINKAGE TO DOS
PUSH DS ; DO
MOV AX,0 ;
PUSH AX ; NOT
MOV AX,MAIN_DATA ;
MOV DS,AX ; ALTER!
CALL READ_FILE ;READ AND DISPLAY THE FILE
RET
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
;ROUTINE READ_FILE
;
;
; BRIEF:
; READS THE FILE "A:JUNK.TXT" AND DISPLAYS IT ON THE SCREEN.
;
; INPUT:
; RECORD_LENGTH: THE NUMBER OF BYTES TO READ FROM THE FILE
; WITH EACH READ OPERATION.
;
; THE ASCIIZ STRING "FILE" CONTAINING THE FILE TO BE READ.
;
; AN INPUT DATA AREA (IO_AREA) WHERE EACH RECORD READ FROM
; THE FILE IS BUFFERED.
;
; OUTPUT:
; THE FILE "A:JUNK.TXT" IS DISPLAYED ON THE SCREEN.
;
;------------------------------------------------------------------------------
READ_FILE PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
;--OPEN THE FILE "A:JUNK.TXT" FOR READING. THIS CALL SETS THE READ/WRITE
; POINTER TO THE FIRST BYTE OF THE FILE, AND SETS THE RECORD SIZE TO ONE
; BYTE.
;
; ON RETURN AX HAS THE HANDLE (WORD POINTER) ASSOCIATED WITH THE FILE.
MOV AH,3DH ;REQUEST "OPEN FILE" SERVICE
MOV AL,0 ;FILE OPENED FOR READING
MOV DX,OFFSET FILE ;DS:DX -> FILE TO BE READ
INT 21H ;INVOKE "OPEN FILE" SERVICE
;--SAVE FILE HANDLE IN BX REGISTER.
MOV BX,AX ;BX -> FILE HANDLE
;--PERFORM ALL DISK TRANSFERS TO IO_AREA
MOV CX,RECORD_LENGTH ;CX HAS NUMBER OF BYTES TO READ
MOV DX,OFFSET IO_AREA ;SET DS:DX -> TO IO_AREA
REA1: MOV AH,3FH ;REQUEST "READ" SERVICE
INT 21H ;INVOKE "READ" SERVICE
CMP AX,0 ;AX HAS NUMBER OF BYTES READ
JE REA2 ;READ END OF FILE
;--WRITE "IO_AREA" TO SCREEN (RECALL DS:DX -> IO_AREA)
MOV AH,9 ;REQUEST "PRINT STRING" SERVICE
INT 21H ;INVOKE "PRINT STRING" SERVICE
JMP REA1 ;READ NEXT BYTE
;--AX = 0, SO END-OF-FILE READ. CLOSE FILE HANDLE AND LEAVE.
REA2: MOV AH,3EH ;REQUEST "CLOSE FCB" SERVICE
INT 21H ;INVOKE "CLOSE FCB" SERVICE
POP DX
POP CX
POP BX
POP AX
RET
READ_FILE ENDP
;------------------------------------------------------------------------------
MAIN ENDP ;END of MAIN procedure
CODE ENDS ;END of CODE Segment
END MAIN ;END of assembly.
┌──────────────────────────────────┐
│ Closing Thoughts │
└──────────────────────────────────┘
In both programs, one byte was read with each read
operation to help locate the EOF marker. Reading a file one
byte at a time, without any further processing of this byte,
causes no noticeable speed degradation, as DOS buffers all
file input/output.
But if each byte must be inspected for special
characters, speed degradation can be significant. For
example, disk space can be conserved by compressing "blanks"
in source files to tab characters when the file is saved.
When this file is later read, each byte must be examined,
and if a tab is found, expanded to the appropriate number of
blanks. This is a time-consuming process and in this case
it is best to read a block (or group) of data with each read
operation. Once in memory, this block can be divided into
individual bytes and each byte examined.
(I have experimented using different RECORD_LENGTH
values and the results can be startling. Using a
RECORD_LENGTH of 1, a large file took 30 seconds to read and
uncompress, one byte at a time, while with RECORD_LENGTH =
80, it took on 5 seconds! I also found, as was expected,
that RECORD_LENGTHs significantly larger than 80 did not
substantially improve this 5 second time. It's fun to
experiment.)
My next article on file handling deals with Random I/O.
Sequentially yours,
Bill Salkin
┌──────────────────────────────────┐
│ File Name: ██ asm2.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ Simpmaze Documentation ║
║ ║
║ by ║
║ ║
║ Bill Salkin ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Introduction │
└──────────────────────────────────┘
Simpmaze is a maze-generation program created by Dan
Rollins. This article presents an overview of the source
code. For a full description, see the article "PolyMaze!
Solver" in the December 1983 issue of Creative Computing.
┌──────────────────────────────────┐
│ Sample Run │
└──────────────────────────────────┘
A sample run of Simpmaze looks like this.
┌──────────────────────────────────────────────────────────────┐
│ SIMPMAZE ... Generic Maze Generation │
│ Public domain program written by Dan Rollins 04/05/83 │
│ │
│ horizontal size (26 fits on screen)? 4 │
│ vertical size (11 fits on screen)? 3 │
│ calculating maze... please be patient │
│ │
│ + +--+--+--+ │
│ I I I │
│ + +--+--+ + │
│ I I I I │
│ + + + + + │
│ I I I │
│ +--+--+--+ + │
│ │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────┐
│ Coordinate System Used │
└──────────────────────────────────┘
The following coordinate system is used in Simpmaze:
X
(0,0) .───────────>
│
│
│
Y │
v
The origin of the coordinate system is in the upper
left-hand corner; X increases as we move eastward, and Y
increases as we move southward.
┌──────────────────────────────────┐
│ An AMazing Floorplan │
└──────────────────────────────────┘
Think of a maze as a floorplan for a building where
each room has precisely two openings (an entrance and an
exit). While constructing the maze, though, Simpaze assumes
that a room has four doors, and determines which door can
act as an exit and which door can act as an entrance.
┌──────────────────────────────────┐
│ The Array MZ │
└──────────────────────────────────┘
A convenient method is needed to determine which doors,
if any, are open in a room. If the upper left-hand
coordinate of the room is (X,Y), then the value of MZ(X,Y)
provides this information in a numeric manner that is easy
to manipulate.
For each room in a maze, an open east door is
associated with the number 2; an open west door with 8; an
open south door with 4; an open north door with 1. (The
value of zero is associated with a closed door.) This is
shown below.
1
┌────/────┐
8 / / 2 MZ(X,Y) = 1 + 2 + 4 + 8 = 15
└────/────┘
4
Simpmaze initially sets MZ = 0 for each room in the
maze, and for any open door adds the corresponding numerical
value to the current value of MZ(X,Y). If only the north
door of a room is open, then MZ(X,Y) is set equal to 1. If
only the east and west doors are open, MZ(X,Y) = 2 + 8 = 10.
In the above illustration, all doors are open so MZ(X,Y) is
the sum of 1,2,4, and 8 as shown.
┌──────────────────────────────────┐
│ The Program Simpmaze │
└──────────────────────────────────┘
The values entered above (in the sample run) for the
horizontal and vertical size are called H and V,
respectively, in Simpmaze.
A random starting point is determined using these
values as seeds. Simpmaze closes all doors on all the rooms
in the maze with the statement:
1000 FOR J=0 TO H :FOR K=0 TO V :MZ(J,K)=0 :NEXT :NEXT '** "close" all doors
The idea behind Simpmaze is: proceed to a room and
check if it has any open doors. If an open door is found,
do not enter this room. In this manner, we never enter a
room that has been previously visited, and when the number
of rooms entered equals the total number of rooms, the maze
has been solved. (If we are trapped, that is, if all
adjacent rooms have been visited, the program scans the maze
for an unvisited room, and, if found, we proceed to that
room.)
Assume that the upper left-hand corner of a room has
coordinates (X,Y) and we are positioned near this corner.
To test whether the room to the north has a closed door use:
1030 IF Y>0 THEN IF MZ(X,Y-1)=0 THEN Q=Q+1 :T(Q)=0 '** North
(Think of the vector from (X,Y) to (X,Y-1) with the tip at
the latter point. This vector points to the north as Y
decreases in the northward direction.)
If the north door is closed, then we can move to the
north and this is indicated by setting the value T(1) to 0.
Next, the other possible directions of movement are checked:
1040 IF X<H THEN IF MZ(X+1,Y)=0 THEN Q=Q+1 :T(Q)=1 '** East
1050 IF Y<V THEN IF MZ(X,Y+1)=0 THEN Q=Q+1 :T(Q)=2 '** South
1060 IF X>0 THEN IF MZ(X-1,Y)=0 THEN Q=Q+1 :T(Q)=3 '** West
When all possible directions have been tested, a
particular direction is selected by:
1100 D=INT(RND*Q)+1 :DIR=T(D) '** choose randomly from list
To exit this room in the direction given by DIR, we
open the door in the current room using:
1110 MZ(X,Y)=MZ(X,Y) + PWR2(DIR) '** add door in current room
Notice from line 1030-1060 that
T(Q)
if T(Q) = 0, then 2 = 1 = an open north door
T(Q)
if T(Q) = 1, then 2 = 2 = an open east door
T(Q)
if T(Q) = 2, then 2 = 4 = an open south door
T(Q)
if T(Q) = 3, then 2 = 8 = an open west door
The association between the values of T, the mysterious
PWR2 (power of 2) function, and the potential open doors has
been clarified.
The values of X and Y are updated to reflect our move
to the new room by:
1120 Y=Y+YD(DIR) :X=X+XD(DIR) '** move to new room
where XD, YD values are essentially 0, 1, or -1.
When we open, say, the north door in the current room
for an exit, to complete the passage we must open the south
door in the new room as an entrance.
To amplify this last statement, notice in the diagram
below that exiting the bottom room through the north door
requires entering the adjacent room through the south door.
┌─────────┐
│ │
└────/────┘ S
┌────/────┐ N
│ │
└─────────┘
This complementary direction is given by the statement:
1130 ND=DIR-2 :IF ND<0 THEN ND=4+ND '** opposite DIR for New Dir
The door in the new room is opened by:
1140 MZ(X,Y)=MZ(X,Y) + PWR2(ND) '** add door in new room
The room count is updated to reflect that we have
entered a new room by:
1150 RC=RC+1 '** update Room Count
Finally, when the room count equals the total number of
available rooms, the calculations have been completed and
the maze is drawn.
┌──────────────────────────────────┐
│ Drawing the Maze │
└──────────────────────────────────┘
To draw the maze, we need only draw the north and west
doors for, as mentioned above, the south door of one room is
essentially the north door of the room beneath it.
Two simple facts about MZ are used to draw the maze.
1. If MZ(X,Y) is odd, then the room must have an open
north door. (The only way MZ can be odd is if the
number 1 has been added to it; that is, a north
door was opened.)
2. If MZ(X,Y) > 7 then a west door must be open. For
the sum of the values associated with the other
three doors is 7 (1 + 2 + 4), and the only way to
exceed this value is by having a west door open.
The code that draws the maze is:
2010 FOR Y=0 TO V
2020 FOR X=0 TO H
2030 IF INT(MZ(X,Y)/2)=MZ(X,Y)/2 THEN PRINT "+--"; :GOTO 2050
2040 PRINT "+ "; '** must have a North door
2050 NEXT X :PRINT "+"
2060 FOR X=0 TO H
2070 IF MZ(X,Y) > 7 THEN PRINT" "; :GOTO 2090 '** must be a West door
2080 PRINT"I ";
2090 NEXT X :PRINT "I"
2100 NEXT Y
To complete the drawing, the door in the southeastern
corner of the maze is opened as an exit and the program is
complete.
┌──────────────────────────────────┐
│ File Name: ██ basic1.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ Introduction to C ║
║ ║
║ by ║
║ ║
║ Ron Watson ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Introduction │
└──────────────────────────────────┘
Welcome to the C tutorial. This column will provide
instruction in how to use this powerful language. It is
aimed at experienced programmers and so will not cover
programming principles. This column is essentially a diary
of the author's experience while studying the language,
using several sources. Frequent reference will be made to
"The C Programming Language" by Kernighan and Ritchie (K&R)
which is the C "Bible."
┌──────────────────────────────────┐
│ Good and Bad News │
└──────────────────────────────────┘
C was developed as a tool for systems programmers and,
unlike most other languages, was defined by experienced
programmers for their own use. This is both good and bad
news. The good news is that the language has very few
limitations; the bad news is that in the attempt to create a
very terse language (systems programmers do not like to
type) they evolved some syntax that can become painfully
obscure.
Like nuclear energy, the results can be very useful or
downright destructive, depending on who is using it for what
purpose. Usually, there will be several ways to express the
same algorithm, including two or three alternatives that
generate precisely the same object code. This freedom of
expression can mean great fun for the original programmer
and many sleepless nights for the poor slob who has to
change it some years later.
Because of the immense freedom and power of the
language, the responsible programmer will exercise
discipline to establish and maintain consistency of style
and method or his programs will be too expensive to
maintain.
┌──────────────────────────────────┐
│ Portability │
└──────────────────────────────────┘
One reason for C's recent rise in popularity is its
supposed ability to be converted for use on new machines, a
feature known as "portability." This belief may be so
widespread because those making the judgment are comparing C
to assembly language. Another reason may be the generous
choice of C compilers available for nearly every
cpu/operating system combination on the market.
The C language was intended to be machine-independent
and toward that end contains no definition for input/output
commands; they are implemented in functions, the detailed
operations of which can be changed without affecting the
operation of the main program. That was the plan, anyway.
In fact, there can be considerable difficulty transporting a
C program between two different compilers implemented on the
same machine under the same operating system.
The methods used by various software companies to
implement "standard" compilers are very different. So be
warned. If you want to write programs that are easily moved
between machines, choose a compiler that is available on all
the machines you want to use; make sure the compiler chosen
adheres to the standards defined in K&R. Also, keep all
input/output operations in independently defined and
compiled functions, especially those that use the display
and/or keyboard.
With these caveats and a little luck you might be able
to "port" your program to the next generation of desktop
computers without rewriting 80% of the code. The examples
used in this column have been compiled and tested using the
Lattice C compiler. This compiler meets the restrictions
mentioned above but is not the only one that does. I will
try to indicate any potential portability problems with each
example.
┌──────────────────────────────────┐
│ The Simplest C Program │
└──────────────────────────────────┘
We begin our study of C with an example of the simplest
possible C program, one that does nothing at all. (The
example was originally provided to the Department of Defense
by a contractor at a cost of slightly less than 1.3 million
dollars.)
main()
{
}
Small as it is, it demonstrates several characteristics
of the language that must be understood. The word "main" is
the name of the program, and every complete C program must
contain one and only one of these; the language is
case-sensitive, so "main" must be in lower case. The "()"
can contain the definition for a list of parameters passed
by the operating system and must appear even if the list is
null. The left and right braces "{ }" mark the beginning
and end of a block of code. Spaces, tabs, carriage returns,
and line feeds, collectively known as "white space," are
ignored, so the example could be written as:
main(){}
┌──────────────────────────────────┐
│ Introduction to Printf │
└──────────────────────────────────┘
A more complicated example - one that actually does
something - is presented next. This example adds one line
of code to the first example, a function call, to print
"hello, world" on the standard output unit. (This is the
first example given in the K&R tutorial.)
main()
{
printf("hello, world\n");
}
The additional line introduces several new features of
the language. Notice the semicolon at the end of the line;
this character is used to mark the end of each statement.
Of particular importance is the method of calling
functions. There is no verb such as "call" or "perform" or
"gosub" used to invoke a subroutine or external procedure.
Instead, merely write the name of the routine, followed by
left and right parentheses. The routine being used,
"printf," is a standard output routine provided with every C
compiler. In the form shown, it will display the string
"hello, world", followed by a "new line" on the standard
output device.
This example demonstrates one of the design concepts of
C, namely, the omission from the language of any
input/output keywords; all such operations are accomplished
with function calls such as printf.
┌──────────────────────────────────┐
│ The Escape Character │
└──────────────────────────────────┘
The "\" is called the "escape character," and is used
in various circumstances to facilitate the entry of special
characters into a program. We will discuss the "\n"
sequence later, as it is potentially troublesome when moving
between machines. For now, it is sufficient to say that it
will yield a carriage-return, line-feed sequence on the PC.
If it were omitted from the example, the cursor would remain
after the "d" in "hello, world" instead of going to the
first column of the following line.
Observe the use of the double-quote character to
delimit a string. Although this example does exactly what
it appears to do, the code generated is somewhat different
than an intuitive examination might conclude. It is not
important at this point in the discussion; just bear in mind
that what you see is not always what you get.
┌──────────────────────────────────┐
│ Test Your Compiler │
└──────────────────────────────────┘
If you are reading this with the intention of learning
how to program in C, I suggest that you stop at this point
and run the above example through your compiler. Trivial as
it appears, it gives the opportunity to: be sure you know
how to use your compiler, check that it is installed
correctly, that the output from your text editor is
compatible with your compiler, and that you really do
understand the principles demonstrated.
If your compiler is not capable of producing the
expected results from the example, as shown, you should find
another compiler. If you are using DOS 2.0, try to
re-direct the output from the example to the printer or a
disk file. While not absolutely critical, re-direction can
be a very useful debugging aid.
By way of experiment, you might create a few deliberate
errors to see how your compiler reacts. Leave off the
terminal semicolon or one of the quotation marks; throw in
an extra brace, or spell "main" in capital letters. To get
a better understanding of the "printf" function, restate the
program as:
main()
{
printf("hello");
printf(", world");
printf("\n");
}
This should give the same results as the previous
example.
Now that you understand the basic structure of a C
program, we can proceed to discuss data representation and
variables.
┌──────────────────────────────────┐
│ Data Representation │
└──────────────────────────────────┘
The language requires that every variable used must
first be declared, and most compilers require the
declarations to appear in the source program before the
first executable statement. The permissible types will vary
somewhat between compilers, but the types "char" and "int"
are always available. The adjectives long, short, and
unsigned can usually be applied to int to modify its
definition. The types float and double are also available,
but not with every compiler. The lengths of each data type
are allowed to vary according to the language definition,
depending on the machine being used. In 8086/8088
implementations: a "char" is 8 bits or 1 byte, "int" is 16
bits or 2 bytes, "float," when available, is 32 bits, and
"double" is 64 bits. A long int is 32 bits and a long float
should be the same as a double.
┌──────────────────────────────────┐
│ Integer Variables │
└──────────────────────────────────┘
The following program demonstrates how an integer
variable is declared and printed:
main()
{
int izero, imin, imax;
izero = 0;
imin = -32768;
imax = 32767;
printf("Integers = %d %d %d\n",izero,imin,imax);
}
There are several new concepts here. Study the manner
in which variables are declared in the first line. The
keyword "int" is followed by the names of variables to be
defined, separated by commas. This line is terminated with
a semicolon. The statement on this line could span three or
four lines, with white spaces placed anywhere desired.
The next three lines are used to assign values to the
variables. The "=" is the assignment operator which
requests that an evaluation of the right side of the
equation be stored in the variable named on the left. The
"%d", in the string passed to printf, is a format code that
tells printf how to display the variables izero, imin, and
imax.
This example should begin to give you a hint as to how
powerful the printf function can be. The first parameter,
the quoted string, contains data to be printed along with
control information used to format variables. It works
somewhat like a Fortran or PL/I format statement, though
simpler. The "%" is used to indicate the presence of a
format description. The format string is followed by a list
of variable names to be edited into the output. The example
above shows the format string with three "%d"s and three
variable names; in general, there should be as many "%"
codes in the string as there are variable names following
it. The "%' code and the variables names are in one-to-one
correspondence.
The "d" format code will cause an integer to be edited
into the output in the position occupied by the "%d". The
first "%d" is associated with the variable "izero", the
second "%d" with "imin," and the last "%d" with "imax."
More examples of the printf statement will be given later.
┌──────────────────────────────────┐
│ Character Variables │
└──────────────────────────────────┘
Let's expand on the last program to demonstrate the use
of "char," or character variables:
main()
{
int izero, imin, imax;
char cha, chb, chc;
izero = 0;
imin = -32768;
imax = 32767;
cha = 'a';
chb = 'b';
chc = 'c';
printf("Integers = %d %d %d\n",izero,imin,imax);
printf("Characters = %c %c %c",cha,chb,chc);
}
The most important thing to note in this example is
that a char type variable can contain only one character;
there is no way to define a character string variable except
as an array of single characters.
Notice that whereas the double quote (") has been used
to define a string for the printf function, the single quote
('), or apostrophe, is used to assign values to the
character variables. The distinction is important. The
double quote denotes a character string terminated by a
binary zero; the single quote can only denote a single
character. You can request a character string constant by
using double quotes, but there is no way to define a
character string variable except as an array of
one-character elements. This turns out not to be as silly
as it sounds, but it takes some getting used to,
particularly if you are accustomed to PL/I or Basic.
Unlike those languages, C does not maintain information
about string length but rather defines all strings as having
a variable length terminated by a binary zero. This gives
the programmer considerable control over more complicated
string manipulations at the expense of complicating the
simpler operations. As we will see, there is no direct
string assignment operator; the operation must be performed
by a function which is provided by any decent compiler as
part of its library.
At this point, recompile this program to be certain you
understand the principles involved. After it compiles
error-free, purposely introduce errors, such as omitting a
"%d" or "%c" from the printf format string. For more
exciting results, insert an extra format code in the string,
so there are more "%d" characters than variable names
following the format string.
┌──────────────────────────────────┐
│ Conclusion │
└──────────────────────────────────┘
In my next column, program control and looping is
discussed. This will provide the additional tools we need
to study string processing in C.
┌──────────────────────────────────┐
│ File Name: ██ c1.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ║
║ Enhancements to PCFL/PCUG ║
║ ║
║ ║
╚═════════════════════════════════════════════════════════════════════════════╝
1. Beginning C column by Ron Watson
┌────────────────────────────────────────────────────────────┐
│ │
│ ╔═════╗ │
│ ║ ╨ │
│ ║ │
│ ║ │
│ ║ │
│ ║ ╥ │
│ ╚═════╝ │
│ │
└────────────────────────────────────────────────────────────┘
2. Demonstration programs, FREEWARE(tm), etc.
┌────────────────────────────────────────────────────────────┐
│ ╥ │
│ ║ │
│ ╔════║═ ╔════╗ ╔╗ ╔╗ ╔════╗ ╔════╗ │
│ ║ ║ ║ ╨ ║╚╗╔╝║ ║ ╔╗ ║ ║ ╨ │
│ ║ ║ ╠═╣ ║ ║║ ║ ║ ║║ ║ ╚════╗ │
│ ║ ║ ║ ╥ ║ ╚╝ ║ ║ ╚╝ ║ ╥ ║ │
│ ╚════╝ ╚════╝ ╨ ╨ ╚════╝ ╚════╝ │
│ │
└────────────────────────────────────────────────────────────┘
3. Beginning FORTH column by Guy Kelly. (FORTH processor also supplied!!)
┌────────────────────────────────────────────────────────────┐
│ │
│ ╔═════╗ │
│ ║ ╨ │
│ ║ ╔════╗ ╔════╗ ╔══╦══╗ ╥ ╥ │
│ ╠══╣ ║ ╔╗ ║ ║ ║ ╨ ║ ╨ ║ ║ │
│ ║ ║ ║║ ║ ╠══╦═╝ ║ ╠════╣ │
│ ║ ║ ╚╝ ║ ║ ╚═╗ ║ ║ ║ │
│ ╨ ╚════╝ ╨ ╨ ╨ ╨ ╨ │
│ │
└────────────────────────────────────────────────────────────┘
4. Improved screen scrolling
┌────────────────────────────────────────────────────────────┐
│ ╔════╗ │
│ ║ ╨ │
│ ║ ╔════╗ ╔════╗ ╔════╗ ╥ ╥ │
│ ╚════╗ ║ ╨ ║ ║ ║ ╔╗ ║ ║ ║ │
│ ║ ║ ╠══╦═╝ ║ ║║ ║ ║ ║ │
│ ╥ ║ ║ ╥ ║ ╚═╗ ║ ╚╝ ║ ║ ╥ ║ ╥ │
│ ╚════╝ ╚════╝ ╨ ╨ ╚════╝ ╚═════╝ ╚═════╝ │
│ │
└────────────────────────────────────────────────────────────┘
┌──────────────────────────────────┐
│ Numeric Keypad │
└──────────────────────────────────┘
┌────┐ ┌────┐ ┌────┐ ┌────┐
│7 │ │8 │ │9 │ │ │
│ │ │ │ │ │ │ │ "Upward" movement in file
│Home│ │ │ │PgUp│ │ - │
└────┘ └────┘ └────┘ └────┘
┌────┐ ┌────┐ ┌────┐ ┌────┐
│4 │ │5 │ │6 │ │ │
│ │ │ │ │ │ │ │
│<- │ │ │ │ -> │ │ │
└────┘ └────┘ └────┘ │ │
┌────┐ ┌────┐ ┌────┐ ├────┤
│1 │ │2 │ │3 │ │ │
│ │ │ │ │ │ │ + │ "Downward" movement in file
│End │ │ │ │PgDn│ │ │
└────┘ └────┘ └────┘ ├────┤
│ │
│ │
│ │
│ │
└────┘
┌──────────────────────────────────┐
│ "Upward" Movement │
└──────────────────────────────────┘
┌────┐
│7 │ ▄▄▄▄
│ │ ▄▄▄▄ move screen to top of file
│Home│
└────┘
┌────┐
│8 │ ▄▄▄▄
│ │ ▄▄▄▄ scroll up 1 line
│ │
└────┘
┌────┐
│9 │ ▄▄▄▄
│ │ ▄▄▄▄ scroll up 1/2 page
│PgUp│
└────┘
┌────┐
│ │ ▄▄▄▄
│ │ ▄▄▄▄ scroll up 1 page
│ - │
└────┘
┌──────────────────────────────────┐
│ "Downward" Movement │
└──────────────────────────────────┘
┌────┐
│1 │ ▄▄▄▄
│ │ ▄▄▄▄ move screen to bottom of file
│End │
└────┘
┌────┐
│2 │ ▄▄▄▄
│ │ ▄▄▄▄ scroll down 1 line
│ │
└────┘
┌────┐
│3 │ ▄▄▄▄
│ │ ▄▄▄▄ scroll down 1/2 page
│PgDn│
└────┘
┌────┐
│ │
│ │
├────┤ ▄▄▄▄
│ + │ ▄▄▄▄ scroll down 1 page
├────┤
│ │
│ │
└────┘
5. Split-files to split double-sided PCFL disks into single-sided ones.
┌────────────────────────────────────────────────────────────┐
│ ╔════╗ │
│ ║ ╨ │
│ ║ ╔════╗ ╥ ╥ ╔══╦══╗ │
│ ╚════╗ ║ ║ ║ ║ ╨ ║ ╨ │
│ ║ ╠════╝ ║ ║ ║ │
│ ╥ ║ ║ ║ ╥ ║ ║ │
│ ╚════╝ ╨ ╚═════╝ ╨ ╨ │
│ │
└────────────────────────────────────────────────────────────┘
Double-sided = Single-sided + Single-sided
┌───────────┐ ┌───────────┐ ┌───────────┐
│ Disk A │ │ Disk AA │ │ Disk AAA │
│ │ ▄▄▄▄ │ │ ▄ │ │
│ o │ ▄▄▄▄ │ o │ ▄▄█▄▄ │ o │
│ ▐█ │ │ ▐█ │ █ │ ▐█ │
│ ▐█ │ │ ▐█ │ │ ▐█ │
└───────────┘ └───────────┘ └───────────┘
6. All file identification banners now appear at the bottom of the file.
┌────────────────────────────────────────────────────────────┐
│ │
│ ┌──────────────────────────────────┐ │
│ │ File Name: ██ rescue.me ██ │ │
│ └──────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────┘
┌──────────────────────────────────┐
│ File Name: ██ changes.txt ██ │
└──────────────────────────────────┘
╔═════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ║
║ Copyright 1984 by ABComputing. ALL RIGHTS RESERVED ║
║ ║
║ ║
╚═════════════════════════════════════════════════════════════════════════════╝
PC FIRING LINE/PC UNDERGROUND, or portions thereof, are
not to be sold or used in a product for sale without the
written consent of ABComputing. The only exception is that
small excerpts may be used for critical review.
Copies may be made for non-profit use.
If clarification is required, contact ABComputing at
P.O. Box 5503, North Hollywood, CA 91616-5503. Or phone
(818) 509-9002.
Associations that aid the handicapped are encouraged to
contact us if our material, in any form, can be of value.
┌──────────────────────────────────┐
│ DisKclaimer │
└──────────────────────────────────┘
We cannot guarantee the accuracy of, or assume
responsibility for, information on a diskette. All source
code and text is used at your own risk.
┌──────────────────────────────────┐
│ File Name: ██ cpyright.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ DOS - Past, Present, and Future ║
║ ║
║ by ║
║ ║
║ Don Buresh ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Introduction │
└──────────────────────────────────┘
Greetings. I have been looking forward to writing this
article because it is about the birth and growth of PC-DOS.
This article is fun for me to write because I have been
involved with PCs from their introduction in October 1981.
I was teaching COBOL programming at a private school
when I read an announcement about the IBM-PC in the Boston
Globe. I was expecting a microcomputer that had the power
of a mainframe and was the size of a briefcase. After
learning about the Intel 8088 processor, I realized that IBM
had a winner! This CPU can address one megabyte of random
access memory and can be used in conjunction with the Intel
8087, a numeric co-processor. These two facts convinced me
to purchase an IBM-PC.
I bought my PC in February of 1982 and was terrified by
the machine. My computing experience involved mainframes
exclusively where a programmer was not even allowed to touch
the machine, let alone have the ability to open up the box
and examine the innards. For the first two months it sat on
my desk while I tried to understand BASIC and the PC-DOS
manual. I quickly grasped BASIC and then purchased the
IBM-PC assembler.
In the next six months I immersed myself in i8088
assembly language and the listing of the PC ROM contained in
the Technical Reference Manual. After much work, I realized
that the IBM-PC assembler was not used to generate the ROM,
since it would not permit me to put a label in a program by
itself. I remember learning how to perform I/O operations
on a diskette, using INT 13H, over Thanksgiving. It seemed
like an impossible task that would never be completed.
During this time I was writing and marketing a disk
utility, that met with marginal success. For financial
reasons, I took a contract with a Boston area computer
company that was developing a PC-compatible microcomputer; I
worked on their ROM. From this unique perspective, I saw
PC-DOS grow into the mature product that it is today. After
the contract was over, I continued to develop IBM-PC
software for companies in the Boston area. I am currently
contracting with a Boston area company that is writing an
integrated software package for the IBM-PC and other
microcomputers.
┌──────────────────────────────────┐
│ PC-DOS 1.0 │
└──────────────────────────────────┘
When IBM-PC DOS 1.0 was introduced, it contained
several commands and limited batch processing facilities.
About half of the commands were internally part of PC-DOS,
while the disk utilities were external assembly language
programs. These commands are listed below:
┌──────────────────────────────────┐
│ CHKDSK COMP COPY │
│ DATE DIR DISKCOMP │
│ DISKCOPY ERASE FORMAT │
│ MODE PAUSE REM │
│ RENAME SYS TIME │
│ TYPE │
└──────────────────────────────────┘
These commands were written for a single-sided diskette
with forty (40) tracks and eight (8) sectors per track. The
track numbers start with track zero (0) and end with track
thirty-nine (39). The sector numbers within a track begin
with sector one (1) and end with sector eight (8).
PC-DOS also came with interpretive BASIC, a text editor
called EDLIN, a LINKer, a DEBUGger, and a series of BASIC
programs. All of these programs were sold on one
single-sided floppy diskette.
In May 1982, PC Magazine published its first issue.
Users groups were quickly forming across the nation. People
immediately noticed that the IBM-PC and the PC-DOS could
handle only single-sided diskettes. This was seen as a
clear disadvantage at the time. However, people were
hopeful because the PC was the first inexpensive
microcomputer that used the Intel 8088 CPU chip.
Furthermore, the information coming out of Boca Raton
indicated that IBM was working furiously on a revised PC-DOS
that would be capable of supporting double-sided drives and
diskettes.
At this time, the literature indicated that PC-DOS was
a Microsoft product. However, few people knew that the
operating system was contracted out to Seattle Computer.
This company wrote the disk operating system and the command
parser. When the two programs were submitted to IBM, they
subjected them to an extensive quality-assurance program,
found well over 300 bugs, and decided to rewrite the
programs. This is why PC-DOS is copyrighted by both IBM and
Microsoft. Both companies played a part in the development
of the product.
┌──────────────────────────────────┐
│ PC-DOS 1.1 │
└──────────────────────────────────┘
In the late summer of 1982, IBM introduced their
updated version of PC-DOS. While IBM called the operating
system PC DOS 1.1, Microsoft decided that it could sell the
product to other computer companies that were emerging at
the time. They called their product MS-DOS 1.25 because
there were at least twenty-five (25) documented changes to
DOS.
The major difference between DOS 1.0 and 1.1 is that
the latter can process double-sided diskettes. All of the
external, and most of the internal commands, were rewritten
to accommodate double-sided use.
At the same time, IBM released the Technical Reference
Manual that contained a listing of the firmware and the
hardware specifications of the machine. Producers of both
hardware and software alike pored over this document eager
to learn about the PC; I personally recall studying the
manual day and night. I also read the Intel Data Catalog
which contained all the information in the Technical
Reference Manual, but in greater detail.
When PC-DOS 1.1 was released, IBM included EXE2BIN.EXE
on the DOS diskette. This program converts an .EXE file
into a .COM file. Although this was seemingly an
insignificant addition to the release, it has greatly
increased the productivity of software developers. I recall
my first attempts to use EXE2BIN. As a beginner, I had a
difficult time coordinating MASM, LINK and EXE2BIN to
produce a .COM file. The secrets to creating a .COM file
are:
┌──────────────────────────────────────────────┐
│ 1. Put all of the code and data in one │
│ segment │
│ │
│ 2. Do not fix up any segment register values │
│ in the assembly language code; and │
│ │
│ 3. Use ORG 100H in the beginning of the │
│ assembly language code to make room for │
│ the Program Segment Prefix required by │
│ PC-DOS. │
└──────────────────────────────────────────────┘
Softalk and Personal Computer Age were the next major
magazines to arrive on the scene. The editors of both
publications wanted a technically competent magazine that
would serve as an alternative to PC Magazine. In the course
of a year, both magazines have achieved their objective.
While IBM and Microsoft were busy creating PC-DOS 2.0,
several small computer companies attempted to cash in on the
popularity of the PC. The first company to bring a PC
compatible to market was Compaq Computer. The founders of
the company were former employees of Texas Instruments who
decided to leave and form their own company. They were
almost ready to bring the Compaq to the marketplace when
Texas Instruments sued Compaq claiming patent infringements.
About a year later, the case was settled out of court.
During this period I was working for another company
developing a PC compatible microcomputer. I ensured that
the firmware was functionally equivalent to that of the
IBM-PC. We struggled with a series of issues that can
make-or-break compatibility between machines. A detailed
discussion of these issues is provided in another article in
this section.
┌──────────────────────────────────┐
│ PC-DOS 2.0 │
└──────────────────────────────────┘
In the summer and fall of 1982, IBM and Microsoft were
working on PC-DOS 2.0. PC-DOS 1.1 was entirely rewritten
with the hope of evolving into a significant competitor to
Bell Laboratories' operating system UNIX. (Microsoft had
been licensed to sell their version of UNIX called XENIX.)
The methodology was simple: increase the number of assembly
language functions available through PC-DOS, via INT 21H, so
the C Language can be implemented easily on a microcomputer.
In achieving their objective, IBM and Microsoft tripled
the size of IBMDOS.COM, IBMBIO.COM, and COMMAND.COM. The
new commands available to the operating system were:
┌──────────────────────────────────┐
│ BACKUP BREAK BUFFERS │
│ CHDIR CLS DEVICE │
│ FILES GRAPHICS MKDIR │
│ PATH PRINT RECOVER │
│ RESTORE RMDIR SHELL │
│ TREE VER │
└──────────────────────────────────┘
The major feature of PC DOS 2.0 is the provision for
use of a hard disk and a hierarchical file structure. This
file structure allows one to create, change, and remove
sub-directories. This feature greatly increases the
flexibility of the operating system, making it look almost
like a mainframe.
When IBM released PC-DOS 2.0, they also went to market
with two new versions of the PC. Both products were modified
to correct bugs found in the ROM in early PCs. One product
was the PC/XT, with a 10 megabyte hard disk system that
could use the new file structure supported by PC-DOS 2.0.
In early 1983, two more magazines were being sold on
the newsstands. PC World and PC Technical Journal quickly
established themselves as viable magazines. Both
publications attracted a technical audience that craved more
information about the machine.
┌──────────────────────────────────┐
│ PC-DOS 2.1 │
└──────────────────────────────────┘
The introduction of PC-DOS 2.0 was a major marketing
and system programming feat. Unfortunately, PC-DOS 2.0
contained several annoying bugs that potentially could
destroy the contents of a user's hard disk. IBM released
PC-DOS 2.1 in conjunction with their new product, the PC/Jr.
To date, IBM has met with marginal success in marketing this
operating system and their new home computer.
┌──────────────────────────────────┐
│ The Future │
└──────────────────────────────────┘
The future of the PC lies with the software developers
rather than with IBM or Microsoft. Today a microcomputer is
like a seed planted in the ground. If the software
developers do not create programs for a machine, it is as if
the seed had been planted in rocky soil, tried to grow, and
then died. The IBM-PC is a mature product that was planted
in fertile soil because the software developers created a
large body of programs for the computer.
The operating systems for the PC are migrating toward
UNIX, and the application programs are consolidating to form
integrated software packages. The language of choice is the
C Language created at Bell Laboratories.
The major problems encountered by software developers
are execution speed and program size. Although Lotus 1-2-3
dominates the integrated software market, there are other
companies in the wings attempting to bring their products to
market. At this writing I cannot determine whether the PC
can sustain this trend. It may be that a new and
inexpensive machine must be introduced so that the software
developers can fulfill their dreams.
┌──────────────────────────────────┐
│ Retraction │
└──────────────────────────────────┘
In my last article I stated that IBM wrote COMMAND.COM.
I was mistaken. Microsoft and Seattle Computer are the
companies that created the program.
┌──────────────────────────────────┐
│ User Supported Software │
└──────────────────────────────────┘
Here is an update on the user supported software that I
intend to distribute as a companion to this column. The
disk utility FREECOPY is completed, together with the user's
guide. I am currently working on the source code guide and
expect to have the diskettes available to users' groups in
late April or early May of 1984.
Donald L. Buresh, C.D.P.
┌──────────────────────────────────┐
│ File Name: ██ dos1.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ Is It IBM-PC Compatible? ║
║ ║
║ by ║
║ ║
║ Don Buresh ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Introduction │
└──────────────────────────────────┘
A year ago I was on a development team creating a PC-
compatible microcomputer. I was responsible for assuring
that the firmware was functionally equivalent to the IBM-PC.
I came into the contract with no pre-conceptions on what
constitutes a clone. During the nine months that I stayed
with the company, I learned that a compatible must have the
following features:
┌──────────────────────────────────┐
│ System Architecture │
└──────────────────────────────────┘
The microcomputer must have an IBM-PC bus with an open
architecture. This means that the computer can use memory
and peripheral boards manufactured by companies other than
IBM. Furthermore, it means that the system unit must be
physically large enough to contain these boards.
┌──────────────────────────────────┐
│ Chips │
└──────────────────────────────────┘
The major chips in the microcomputer should be in the
i8088 family. This includes the i8088, i8086, i8186 and the
i8286 processor chips. The computer should also use the
i8272 or NEC 765 disk controller chip, the i8250A
asynchronous or the i8251A synchronous/asynchronous chip,
the i8259A interrupt controller chip, the Motorola 6845 CRT
controller chip, and the i8237 DMA controller chip.
┌──────────────────────────────────┐
│ Numeric Processing │
└──────────────────────────────────┘
The mother board should contain a socket for the i8087
numeric processor chip or the equivalent chip that works
with the other members of the i8088 family of processors.
┌──────────────────────────────────┐
│ Addressing │
└──────────────────────────────────┘
The addresses of all of the I/O ports should be the
same as in the IBM-PC. Although this may not be possible,
depending upon the selection of the peripheral processors,
it is extremely important that the address of the Motorola
6845 be the same, regardless of whether the compatible has a
monochrome or graphics monitor.
┌──────────────────────────────────┐
│ Firmware │
└──────────────────────────────────┘
The numbering of the interrupts should match the IBM-PC
exactly. This issue may not seem worthy to be mentioned;
however, the software engineers for the original DEC Rainbow
started the firmware interrupts at 21H rather than at 01H.
Since the PC-DOS interrupts also begin at 21H, you can
quickly see why the Rainbow ran CP/M exclusively. The later
versions of the hardware corrected this problem, with a
hardware switch.
┌──────────────────────────────────┐
│ Data Segment │
└──────────────────────────────────┘
The data segment for the firmware should contain the
same data items, in the same order, as in the IBM-PC.
Although not a critical issue, software engineers should
make every effort to ensure that the number of bytes in the
compatible's data segment is equal to the number of bytes in
the IBM-PC's data segment. If so, the clone can then run
PC-DOS as well as MS-DOS.
I do recommend that PC-compatible manufacturers add a
Cursor_Address variable to their firmware. If they include
this variable, they can take advantage of the linearity of
Video RAM and improve the speed of the Write Character,
Write Character and Attribute, and Write Teletype functions
of INT 10H.
┌──────────────────────────────────┐
│ Video Ram Segment Address │
└──────────────────────────────────┘
The IBM-PC uses two Motorola 6845s, one for a
monochrome display and another for a graphics display. The
segment address of the monochrome adapter is 0B000H, while
0B800H is the address of the graphics adapter. IBM
designated only one alpha page of video RAM for a monochrome
adapter and eight alpha pages for a graphics adapter.
Furthermore, the IBM-PC has only one graphics plane.
I recommend that a PC manufacturer maintain these
features if at all possible. A small compatibility issue is
the number of graphics planes; more than one graphics plane
is entirely acceptable.
┌──────────────────────────────────┐
│ Interlacing │
└──────────────────────────────────┘
In graphics mode, the IBM-PC uses the following
interlacing scheme to store the scan lines. The even scan
lines begin at relative address 0000H and end at 1F3FH, and
the odd scan lines start at 2000H and end at 3F3FH.
Pictorially,
┌─────────────────────┐ 0000H
│ │
│ even scan │
│ lines │
│ │
├─────────────────────┤ 1F3FH
│ │
│ │
├─────────────────────┤ 2000H
│ │
│ odd scan │
│ lines │
│ │
└─────────────────────┘ 3F3FH
Although interlacing the scan lines in graphics is
essential for compatibility, it is unfortunate that IBM
chose this scheme in the first place. The European Common
Market does not permit hardware manufacturers to sell
computers with interlaced scan lines, as interlacing causes
some eye strain.
Some compatibles, such as the Tandy 2000, do not
interlace scan lines at all. I, for one want IBM to remove
this hardware feature.
┌──────────────────────────────────┐
│ Conclusion │
└──────────────────────────────────┘
These are some of the issues that make a clone a clone.
I probably left out an issue here or there. If so, please
write and tell me.
┌──────────────────────────────────┐
│ File Name: ██ dos2.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ Editorial ║
║ ║
║ by ║
║ ║
║ Bill Salkin - Editor of PCFL/PCUG ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Foreward to the Second Issue │
└──────────────────────────────────┘
Our second issue marks the beginning of substantial
enhancements to PCFL/PCUG; the need for two DS/DD diskettes
is symptomatic of these changes.
A substantial change in our marketing approach has also
occurred. All future issues of PCFL/PCUG must be purchased
from ABComputing; the FREEWARE(tm) principle no longer
applies. This reversal in direction was necessitated by the
increasing daily volume of diskettes received.
Single issues cost $12; $72 for a one-year (six-issue)
subscription. We still encourage you to make copies of each
issue for your friends, and ask that they remit $6 for the
issue to help us defray our expenses.
┌──────────────────────────────────┐
│ Diskette A and Diskette B │
└──────────────────────────────────┘
The second issue of PCFL/PCUG consists of two DS/DD
diskettes called "Diskette A" and "Diskette B." Diskette A
contains the text of PCFL/PCUG, and Diskette B contains DEMO
programs, executable modules, and odds-and-ends which would
not fit on Diskette A.
┌──────────────────────────────────┐
│ Masthead and Table of Contents │
└──────────────────────────────────┘
A masthead and table of contents are now an integral
part of PCFL/PCUG. You can turn to the masthead for a
statement of our pricing structure and a list of
contributing editors.
┌──────────────────────────────────┐
│ Screen Scrolling │
└──────────────────────────────────┘
Screen scrolling has been enhanced. The screen can be
scrolled up or down by one line, a half page, or a full
page. The Home and End keys will move the screen to the top
or bottom of the file, respectively. See the "Enhancements"
section of the Editor's Console for the graphic details.
┌──────────────────────────────────┐
│ New Columns │
└──────────────────────────────────┘
New columns for beginners, in C and FORTH, are included
in this issue, as is a working FORTH processor to boot!
(Excuse my pun. See the FORTH column for details.)
┌──────────────────────────────────┐
│ DEMOnstration Programs │
└──────────────────────────────────┘
The mail we received indicated that DEMO programs could
favorably enhance PCFL/PCUG. DEMOS have now been included
on Diskette B.
In general, DEMOS need not be technically oriented;
database, business-related programs and the like are also
sought.
┌──────────────────────────────────┐
│ "Split" Files │
└──────────────────────────────────┘
"Split" files are batch files that convert the
double-sided PCFL/PCUG diskette into the equivalent
single-sided copies. This is a convenience for those with
double-sided drives who wish to make single-sided copies for
others.
The split file on Diskette A is called "splita.bat",
and the split file on Diskette B is "splitb.bat".
┌──────────────────────────────────┐
│ Where Are the Ads? │
└──────────────────────────────────┘
The space limitation of floppy diskettes forced us to
cancel the ad section in this issue. Happily, it will
return in our next issue, so stop biting your nails!
┌──────────────────────────────────┐
│ Conclusion │
└──────────────────────────────────┘
Keep in touch, as future changes to PCFL/PCUG will be
quite interesting.
┌──────────────────────────────────┐
│ File Name: ██ editor.txt ██ │
└──────────────────────────────────┘
Disk No: 160
Program Title: PC Firing Issue #2
PC-SIG version: 1.1
This is the second issue of PC Firing Line, with the magazine's official
title. It has been positioned as the underground newspaper for the IBM
user. You will be presented with the untold tales and in-depth
programming aids. Some of the articles are ADA, Assembly routines,
LISP, Fortran, and items not written about by IBM. It also contains
many sample program listings with accompanying documentation.
Usage: Reference.
Special Requirements: None.
How to Start: Type GO (press enter).
Suggested Registration: $12.00
File Descriptions:
??? TXT Various information and reviews (22 files).
ADABOOK REV Book reviews on 6 different ADA books.
GRABBAG C Source code for USQ.C.
ITOP LSP Routine converts infix to prefix mathematical expressions.
LISP1 TXT Various mathematical utilities.
LIST1 ADA Various mathematical utilities
LIST1 ASM Various mathematical utilities.
LIST1 BAS Various mathematical utilities
LIST1 C Various mathematical utilities
LIST1 FOR Various mathematical utilities.
PCFL EXE PC-Firing Line main program.
PRETTY1 COM Printer interface routine.
READISCO PE Documentation for READISCOPE program.
SPLITA BAT Splits this diskette for side sided copying.
WRITERS GDE Text file.
PC-SIG
1030D East Duane Avenue
Sunnyvale Ca. 94086
(408) 730-9291
(c) Copyright 1986,87,88,89 PC-SIG, Inc.
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ Roots of 3rd and 4th Order Polynomials ║
║ ║
║ by ║
║ ║
║ William Squire ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Introduction │
└──────────────────────────────────┘
In the 16th century, Italian mathematicians Tartaglia,
Ferrari, and Cardan, developed formulas for solving third
and fourth order polynomial equations, with real
coefficients.
Today, very few computer centers have programs
implementing these solutions. (They rely on iterative
programs that will work for any degree polynomial.) This is
not entirely due to a desire to minimize the number of
subroutines in a library; the "nominally" exact solutions
frequently do not give results as accurate as iterative
solutions.
This column discusses a FORTRAN implementation of the
exact solutions for solving third and fourth order
polynomials. These solutions can be found in an
"Introduction to the Theory of Equations," by N.B.
Conkwright, Ginn Publishers.
┌──────────────────────────────────┐
│ Exact Solution of the Cubic │
└──────────────────────────────────┘
If P3(Z) is a cubic polynomial, with real coefficients
2 3
P3(Z) = C + C X + C X + X
0 1 2
then one root, "X," is given by
X = U + V - (1/3)C (1)
2
where
3
G = ( 2C - 9 C C + 27 C ) / 54
2 1 2 0
2
H = ( 3C - C ) / 9
1 2
2 3 1/2 1/3
U = [ -G + ( G + H ) ] (2)
2 3 1/2 1/3
V = [ -G - ( G + H ) ] (3)
The quantity
2 3
D = G + H
appearing in (2) and (3) is proportional to the discriminant
of the cubic, and indicates the nature of the roots of
P3(Z).
In particular:
if ( D > 0 )
one root is real and two are complex conjugates
elseif ( D = 0 )
all roots are real and at least two are equal
elseif ( D < 0 )
all roots are real and unequal
endif
Note in the case D < 0, all three roots are real, and
that it is necessary to take the cube root of a complex
number in U and V. This may have been an important factor in
convincing mathematicians of the "reality" of so called
"imaginary" numbers.
When D<0, U, and V are complex conjugates, so X is
real.
The cause of inaccuracy of the exact solutions is, in
many cases, the loss of significant digits in U or V when
2 3
G << H
This effect may be minimized by calculating:
2 3 1/2 1/3
U = [ -G + ( G + H ) ]
if -G is positive, or
2 3 1/2 1/3
V = [ -G - ( G + H ) ]
if -G is negative. These forms are chosen so that
essentially no subtraction, only addition, occurs.
When U or V is determined the mate may be found from
UV = - H
and a root determined by (1). Dividing the cubic by
(X-root) yields a quadratic equation that can be solved
easily.
┌──────────────────────────────────┐
│ Exact Solution of the Quartic │
└──────────────────────────────────┘
The quartic equation
2 3 4
P4(Z) = C + C X + C X + C X + X
0 1 2 3
is solved by finding a real root, "Y" of the resolvent
cubic:
2 2 2 3
( 4C C - C - C C )/8 + 1/4 ( C C - 4 C ) X - 1/2 C X + X = 0
2 0 1 3 0 3 1 0 2
Using this real root, the quartic is factored as the
product of two quadratics with real coefficients, and
readily solved. The real coefficients mentioned are
expressions involving "Y".
┌──────────────────────────────────┐
│ Programming Considerations │
└──────────────────────────────────┘
The program accompanying this article implements these
exact solutions. The user is asked whether a cubic or
quartic polynomial is involved, and to provide the
coefficients. The values of the roots are determined and
printed, and the absolute values of P3 and P4 at each root
is printed.
┌─────────────────────┐
│ Cubic Polynomial │
└─────────────────────┘
If a cubic polynomial is requested, subroutine CUBIC is
called. CUBIC calls subroutine CUR to find a real root of
the polynomial, and then QDRTC to find the two remaining
roots.
CUR is a novelty. By treating the various
possibilities separately it produces an accurate result.
1. If D < 0, the exponentiation operator (**) is used to
find the cube root. CUR then uses the complex conjugate of
the cube root in the calculation of the real root.
The difficulty is that one must properly match the
branch of the cube root used for U and V, as the FORTRAN
compiler does not automatically do this. For example, if
asked for a cube root of (-8.,0), the FORTRAN processor may
not give (-2.,0), but one of the complex roots (1,+1.73205)
or (1,-1.73205).
Another difficulty is that the "**" operation does not
work on negative real arguments. The function CBRT(X) is
called from CUR, and it uses SIGN (ABS(X) ** .333333, X) to
find the cube root for both negative and positive X.
Strictly speaking, CBRT is not needed. The necessary code
could be easily inserted in the two places where CBRT is
called, but I believe using CBRT makes the program clearer.
2. If D = 0, the root of the cubic becomes:
1/3
2(-G) - C / 3
2
3. If D > 0, and -G is negative, then V is evaluated and
U is determined from:
U = - H
─────
V
If D > 0, and -G is positive, then U is evaluated and V
is determined from:
V = - H
─────
U
The idea is to match the sign of D to the sign of -G.
In this manner, no subtraction, only addition, is performed.
This approach minimizes round-off error.
┌─────────────────────┐
│ Quartic Polynomial │
└─────────────────────┘
Routine QURTC is called to find the roots of P4. It
uses CUR to find a real root of the resolvent cubic, and
QDRTC is called twice to find the roots of the the two
quadratics mentioned in the section on quartic polynomials.
QDRTC also treats positive, negative, and vanishing
values of the discriminant separately, calculates the first
root (R1), and finds the second root by using
(R1) (R2) = constant term of quadratic
┌──────────────────────────────────┐
│ Conclusion │
└──────────────────────────────────┘
The set of subroutines presented gives accurate results
for a variety of cubics and quartics with real coefficients.
However, three paths were required, depending upon the sign
of the discriminant. Perhaps in the future, improvements in
the complex arithmetic capabilities of compilers will make
it possible to implement the exact solutions for cubics and
quartics with complex coefficients directly.
┌──────────────────────────────────┐
│ File Name: ██ fort1.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ Venture FORTH ║
║ ║
║ by ║
║ ║
║ Guy Kelly ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Introduction │
└──────────────────────────────────┘
Hardware + Software = "Usefulware"
If you are reading this, then very probably your
hardware is an IBM-PC or compatible personal computer. I
deduce from this that the hardware part of our equation is
determined, and the item of interest is the software.
The software component of "usefulware" comes from: (1)
buying it, or (2), writing it. The other option, piracy, is
NOT to be considered!
If you can buy software, why are you reading this
column? Still here? Good! Perhaps you are considering
writing software.
┌──────────────────────────────────┐
│ Hidden Compromises │
└──────────────────────────────────┘
What environment are you going to use to write
software? (Notice I said environment, not programming
language.) Software developers traditionally select a
language that is most suitable (read: most popular, most
glamorous, most inexpensive, etc.) and, most importantly,
one that is available for their hardware and operating
system.
The hidden problem with this approach is that you are
stuck with design decisions as to the features supported by
the language and the operating system. Your programming
environment is totally predetermined. So what?
Suppose you have a great idea for some "usefulware" but
the operating system hampers your access to the hardware,
and the programming language doesn't support the data
structures that you require.
This is not unusual! Try to develop the equivalent of
the Microsoft Flight Simulator package using DOS calls and
BASIC/Pascal/APL/LISP/Ada etc! What to do? How about
C/FORTH/Assembly?
Let's try developing an expert system, such as G.E.
did, for diagnosing problems with diesel locomotives. A
different sort of problem entirely, but would you want to
use BASIC/Pascal/APL/Ada/C/Assembler? Probably not. What
about PROLOG/LISP? FORTH was the choice G.E. made when they
wrote this program, which runs on a PDP 11/23 system.
┌──────────────────────────────────┐
│ The FORTH Environment │
└──────────────────────────────────┘
A traditional FORTH system is more than a language. It
is a complete programming environment which is extensible
both outwardly and inwardly!
Outward extension is accomplished by building an
application language on top of the FORTH system, and then
using the new language to add application layers on top of
the new environment.
Inward extensibility is accomplished by modifying the
structure/capability/features of the FORTH environment - a
process called meta-compilation, i.e., letting FORTH
re-compile a new version of itself. A not too difficult
task, as most of FORTH is written in FORTH, with the
remainder written using the FORTH assembler.
┌──────────────────────────────────────────────────────┐
│ The FORTH Environment is: │
├──────────────────────────────────────────────────────┤
│ │
│ an operating system, │
│ an editor, │
│ an assembler, │
│ an interpreter, │
│ a compiler, │
│ a high-level language, │
│ a set of development tools, │
│ a stack-oriented, traditionally 16-bit machine, and │
│ has simple virtual memory management. │
│ │
└──────────────────────────────────────────────────────┘
┌──────────────────────────────────┐
│ Design Decisions │
└──────────────────────────────────┘
As in other programming environments, FORTH is based on
a series of design decisions concerning the interactions
between the programmer and the computer. The unique set of
decisions, made essentially by one man, have created the
unique programming environment which is FORTH. Some of the
guiding rules in the design of FORTH were:
╔════════════════════════════════╗
║ Rule 1. Keep it simple! ║
╚════════════════════════════════╝
The whole environment is understandable and modifiable
by one person.
╔════════════════════════════════╗
║ Rule 2. Keep it small! ║
╚════════════════════════════════╝
The whole environment can reside in under 16K of
computer memory.
╔════════════════════════════════╗
║ Rule 3. Keep it fast! ║
╚════════════════════════════════╝
Provide an integrated, structured, conditional macro
assembler.
╔════════════════════════════════╗
║ Rule 4. Make it transportable! ║
╚════════════════════════════════╝
FORTH has been put on almost every piece of computer
hardware known.
┌──────────────────────────────────┐
│ FORTH Applications │
└──────────────────────────────────┘
FORTH is best known for its use at Astronomical
Observatories, in process control, and in laboratory
instrumentation. It has also been used as a systems
implementation language by Atari for video games, and by a
diverse group of companies for many applications. There is
even a commercially available FORTH package that compares
favorably with the better program-generating database
languages.
FORTH has been used to write BASIC, Pascal, LISP, LOGO,
COBOL, and FORTH processors, database systems, expert
systems and control systems.
┌──────────────────────────────────┐
│ Origins of the FORTH │
└──────────────────────────────────┘
The best source of information on the origins of FORTH
is contained in Vol. 1, No. 6 of "FORTH Dimensions," pp.
60-75. The article "FORTH The Last Ten Years And The Next
Two Weeks --- " is a printed version of a speech given at
the October 1979, FORTH Convention in San Francisco. The
speech was given by Charles H. Moore, the inventor of FORTH.
In brief, Mr. Moore, in the early 60's, became
dissatisfied with the available programming systems and
began experimenting with a variety of aspects of the
programming environment. By about 1969 he had put together
most of the elements of what is now FORTH. He states, on
page 72: "My original goal was to write more than 40
programs in my life. I think that I have increased my
throughput by a factor of 10. I don't think that throughput
is program-language limited any longer, so I have
accomplished what I set out to do."
The name was chosen to indicate a "fourth" generation
language running on the then "third" generation hardware.
It was spelled FORTH because the file system would allow
only five-character names, and because, as is true in most
file systems, case is disregarded.
┌──────────────────────────────────┐
│ History │
└──────────────────────────────────┘
FORTH has followed several paths to its present state.
Path 1. Mr. Moore had completed the first version of FORTH
at the National Radio Astronomy Observatory. From this
observatory, FORTH spread to Kitt Peak Observatory, and from
there throughout the world of Astronomy until, in 1976, it
was made a standard language for the International
Astronomical Union.
Path 2. In approximately 1969, Charles Moore and Elizabeth
Rather started FORTH, Inc., which produced miniFORTH, then
microFORTH, and eventually polyFORTH and polyFORTH II.
Path 3. Dr. Hans Nieuwenhuijzen, and others at the State
University at Utrecht in the Netherlands, learned of FORTH.
They produced a variety of enhancements and applications and
helped organize the European FORTH Users Group.
Path 4. Bill Ragsdale and others in the San Francisco Bay
became involved with FORTH and formed the FORTH Interest
Group (FIG). They produced a FORTH newsletter named FORTH
Dimensions, and public domain versions of FORTH for five
different microcomputers and the DEC PDP11. Vol. 5, No. 6,
of FORTH Dimensions, pp. 20 - 25, details the formation and
activities of FIG.
Path 5. FORTH, Inc., the European group, and the
Astronomical users joined to produce a 1977 set of standard
FORTH words. (A word in FORTH corresponds to a procedure or
subroutine in other languages.) FIG became involved in 1978
and an updated set of standard words was produced that year.
The Astronomical users then left the standardization
efforts.
In 1979, a charter was proposed and the FORTH Standards
Teams was formed. A 1979 Standard for FORTH was developed
to include the "new" 8-bit machines. The European group
then left the standards team and a group of FORTH vendors
joined the efforts. This changed the makeup of the group
from predominately users to a more equal mix of users and
vendors. In 1982, meetings of the FORTH Standards Team were
conducted to update the 1979 Standard. The updates were so
comprehensive that in 1983 a new standard was released. The
1983 Standard is scheduled for update in 1988.
Path 6. Around 1978, several vendors licensed microFORTH
from FORTH, Inc., and started selling their own versions.
Later, in about 1978-79 (after the release of the public
domain figFORTH), a variety of vendors sold enhanced
versions of figFORTH, then 79 Standard versions, and now the
83 Standard version.
The conclusion to be drawn is that there are many
FORTHs available today, some based on figFORTH, some meeting
earlier standards, and some meeting the 83 standard.
Compatibility between FORTH versions can be a problem but it
is impossible to avoid in an evolving language.
┌──────────────────────────────────┐
│ Information Sources │
└──────────────────────────────────┘
The best source of FORTH literature is Mountain View
Press,Inc., P.O. Box 4656, Mountain View, CA 94040,
(415)961-4103. Their advertisements in Byte magazine, Dr.
Dobbs Journal, and FORTH Dimensions list at least fifteen
books on FORTH, as well as a variety of conference
proceedings and user manuals.
┌──────────────────────────────────┐
│ Books │
└──────────────────────────────────┘
One of the best books on FORTH is "Starting FORTH" by
Leo Brodie, published by Prentice-Hall. It is well written,
contains tutorial examples, and several useful
mini-applications. The version of FORTH that it describes
is a modified polyFORTH with references to figFORTH and to
79 Standard FORTH.
Another contender for best FORTH book is "FORTH Tools"
by Anita Anderson and Martin Tracy, published by
MicroMotion, 12077 Wilshire Blvd., Los Angeles, CA 90025,
(213)821-4340. It, too, is well written and has the
advantage of describing an 83 Standard version of FORTH
which is very similar to two of the 1983 Standard public
domain FORTHs.
┌──────────────────────────────────┐
│ FORTH Magazines │
└──────────────────────────────────┘
There are two magazines devoted exclusively to FORTH:
"FORTH Dimensions," published by the FORTH Interest Group
(P.O. Box 1105, San Carlos, CA 94070), and "The Journal of
FORTH Applications and Research," published by the Institute
for Applied FORTH Research, Inc., (P.O. Box 27686,
Rochester, NY, 14627). A six-issue subscription to FORTH
Dimensions is $15.00.
Another magazine which publishes many articles on
FORTH, and an annual issue devoted to FORTH, is Dr. Dobbs
Journal.
For those who are technically oriented, an excellent
article to read is "An Architectural Trail to Threaded-Code
Systems" by Peter M. Kogge, IBM Federal Systems Division.
It was published in IEEE Computer, March 1982, pp. 22 - 32.
This article builds a logical picture of a FORTH
system, and contains only one minor understatement:
"threaded-code systems should find a secure niche where
small-to-moderate specialized interactive application
packages, real-time control of external devices and sensors,
and engineering-type throw-away code dominate." Companies
such as G.E., with their expert system, Cubic Western Data
with a 2000 screen Navigational package, Computer Software
Design with the Data Ace (a comprehensive database
development package), and several other companies with 5000
screens (5 Megabytes of source code) or larger business
applications have exceeded the "small-to-moderate" size
mentioned.
┌──────────────────────────────────┐
│ FORTH Meetings │
└──────────────────────────────────┘
There are two annual FORTH meetings: (1) The FORML
(FORTH Modification Laboratories) conference at the Asilomar
Conference Center at Pacific Grove Ca., in November and (2)
the Rochester FORTH Applications Conference in June at the
University of Rochester, in Rochester, NY. There are also
regional FIG meetings, usually held monthly, in 47 cities
around the world. If you are interested in attending one of
these meetings, call the FIG hot-line at (415) 962-8653 for
information about the nearest one.
┌──────────────────────────────────┐
│ Other │
└──────────────────────────────────┘
You may have noticed that the word "FORTH" has been
used as a proper name and as an acronym. I have tried to
use the same form as used by the various vendors and
publishers.
┌──────────────────────────────────┐
│ Until Next Time │
└──────────────────────────────────┘
Having mentioned the glittering generalities, in our
next column we discuss the specifics of the FORTH
programming environment and provide examples of FORTH
applications and code. So, as Henry Laxen says, "May the
FORTH be with you."
┌──────────────────────────────────┐
│ File Name: ██ forth1.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ FORTH Reference Documents ║
║ ║
║ by ║
║ ║
║ Guy Kelly ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ The FORTH Environment │
└──────────────────────────────────┘
The file FORTH.OBJ, on Diskette B, invokes the FORTH
environment.
┌──────────────────────────────────────────────────────┐
│ This FORTH Environment is: │
├──────────────────────────────────────────────────────┤
│ │
│ an operating system, │
│ an editor, │
│ an assembler, │
│ an interpreter, │
│ a compiler, │
│ a high-level language, │
│ a set of development tools, │
│ a stack-oriented, traditionally 16-bit machine, and │
│ has simple virtual memory management. │
│ │
└──────────────────────────────────────────────────────┘
This column documents some of the words or features of
1) the FORTH operating systems, 2) the full-screen editor,
and 3) the assembler.
You should regard this documentation as a reference
guide. You will probably be unable to understand it fully
at this time, but it should become useful later.
┌──────────────────────────────────┐
│ Operating System Elements │
└──────────────────────────────────┘
This implementation of FORTH includes the following
FORTH-83 Standard word sets:
┌────────────────────────────────────┐
│ required word set │
│ double number extension word set │
│ assembler extension word set │
│ system extension word set │
│ controlled reference word set. │
└────────────────────────────────────┘
(EDITOR'S NOTE: A "word" in FORTH corresponds to a procedure
or subroutine in other languages.)
Also included are an editor word set and various
display, printing, and tool-set words.
The documentation for the 83 Standard word sets is
contained in the "FORTH-83 Standard," published by the FORTH
Standards Team. It is available from Mountain View Press,
Micro-Motion, and The Institute for Applied FORTH Research,
Inc.
┌──────────────────────────────────────────────────────────┐
│ Documentation Requirements │
├──────────────────────────────────────────────────────────┤
│ │
│ 1. The system dictionary space: type: HERE U. <enter> │
│ │
│ 2. The application dictionary space: SP@ PAD - U. │
│ <enter> │
│ │
│ 3. The data stack space: same as above (shared). │
│ │
│ 4. The return stack space: S0 @ SP@ - 80 - . │
│ │
│ 5. Mass storage used by system: up to 61K on Vol. 0 │
│ │
│ 6. Mass storage available to application: all the │
│ rest, up to block 65534. Block 65535 = buffer │
│ missing. │
│ │
│ 7. Standard PC terminal functions. │
│ │
│ 8. System action on error conditions: │
│ │
│ ' name or ['] name not found = ? error message, │
│ */ */MOD / /MOD divide by 0 = max signed integer │
│ UM/MOD divide by 0 = max integer │
│ : compile error = ? error message │
│ DO compile error = structure error message │
│ EXECUTE improper address error = crash! │
│ EXIT is compile only │
│ FORGET will cause deferred crash if DEFERRED │
│ word or searched vocabulary forgotten │
│ FORTH-83 should work, if it doesn't, let me know! │
│ LOAD issues an error message if block 0 is used. │
└──────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────┐
│ Useful Words │
├────────────────────────────────────────────────────────────────┤
│ Follow all the typed words with an <enter>. │
│ │
│ To list currently active vocabularies type: ORDER │
│ To list the words in the CONTEXT vocab. type: WORDS │
│ To list the source code for a word type: VIEW name │
│ (requires that you have the source disks!). │
│ To list the current volume number type: VOLUME @ . │
│ To update volume number to current disk type: MOUNT │
│ To select the editor type: EDITOR │
│ If you are stuck in an "infinite" loop type: ctrl-break │
│ To list a screen type: n LIST (n = number of screen to list) │
│ To toggle the printer off and on, use ctrl-P. │
│ Note: PRINTER ON and PRINTER OFF also work. │
│ To print a set of screens use n1 n2 SHOW │
│ To select drive b, type: 1DRIVE │
│ To select drive a, type: 0DRIVE │
└────────────────────────────────────────────────────────────────┘
As issued, this version of FORTH is set up for
single-sided drives, with diskettes formatted for 160K per
side. If you have double-sided drives, type: 2 IS #SIDES
<enter>.
The book "FORTH TOOLS Volume 1," by Anita Anderson and
Martin Tracy (published by MicroMotion, 12077 Wilshire
Blvd., Los Angeles, CA 90025, (213)821-4340), is a very
close match to this version of FORTH. It is recommended as
additional documentation. The major differences are in the
area of the editor and in the approach to disk access.
FORTH TOOLS uses DOS files and this version of FORTH uses
the traditional direct disk access via 1024 byte absolute
disk blocks.
┌──────────────────────────────────┐
│ Editor Documentation │
└──────────────────────────────────┘
The Editor provides three basic functions:
Display (To display a screen on the terminal)
Reference (To find a specific character string)
Edit (To modify the contents of a screen)
┌───────────────┐
│ Display │
└───────────────┘
The display command (DISP) displays the specified
screen and puts the system in the display mode. In this
mode, the PgUp and the PgDn keys display the previous or the
next consecutive screen, while the Home key provides entry
to the Edit mode. Any other key will exit from the Display
mode to FORTH (the Space bar will exit without a beep).
(EDITOR'S NOTE: A FORTH screen is 16 lines by 64 columns.)
┌───────────────┐
│ Reference │
└───────────────┘
The Reference mode allows searching for all occurrences
of a string, up to 35 characters, over a specified range of
screens. The DREF command lists all occurrences by screen
and line number. The EREF command displays a screen, enters
the Edit mode, and places the cursor at the beginning of the
screen to allow editing of the screen. All occurrences of
the string are consecutively referenced.
┌───────────────┐
│ Edit Mode │
└───────────────┘
Edit mode is used to modify the contents of a screen.
To invoke the words associated with the editor, type
EDITOR<enter>.
There are four ways to enter the Edit mode:
┌──────────────────────────────────────────────────────┐
│ Type EDITOR<enter> at the system level, then │
│ │
│ 1. type the word EDIT, or │
│ 2. type the word EREF, or │
│ 3. type the word INTO │
│ │
├──────────────────────────────────────────────────────┤
│ │
│ 4. from the Display mode, press the Home key. │
│ │
└──────────────────────────────────────────────────────┘
The cursor position indicates the present mode. In
Edit mode, the cursor is within the screen; in Display mode
the cursor is just below the screen, and when returning to
system mode, is placed several lines below the screen image.
┌───────────────────┬──────────────────────────────────────────────────┐
│ Edit Commands │ Description │
├───────────────────┼──────────────────────────────────────────────────┤
│ n DISP │ Displays screen n and places the system in the │
│ │ Display mode. │
│ │ │
│ n EDIT │ Place the system in the Edit mode with the │
│ │ cursor at the Home position in screen n. │
│ │ │
│ m n DREF cccc │ List all screens and line numbers which │
│ │ contain the string cccc. A space is needed │
│ │ after DREF; m is the first screen to search; │
│ │ n, is the last, and "cccc" represents any │
│ │ string of characters. │
│ │ │
│ m n EREF cccc │ Place the system in the Edit mode and display │
│ │ occurrences of cccc. To continue to the next │
│ │ occurrence of the string, use either ^E or ^Q. │
│ │ ^E = accept any editing changes, ^Q = no-op. │
│ │ A space is needed after EREF. │
│ │ │
│ m n o FROM │ Setup for the INTO command. Displays screen m │
│ │ with lines n through o flagged. │
│ │ │
│ m n INTO │ Moves the lines flagged by FROM into screen m │
│ │ starting at line n and displays the resulting │
│ │ screen with the moved lines flagged and the │
│ │ system in the Edit mode. After any editing │
│ │ the changes are accepted by exiting the Edit │
│ │ mode with a ^E and are rejected by exiting │
│ │ with a ^Q. A single FROM allows multiple │
│ │ INTO's. │
│ │ │
│ m n o SCOPY │ Copies a set of screens. m is the │
│ │ lowest-numbered source screen; n is the │
│ │ lowest-numbered destination screen to be │
│ │ overwritten; o is the count of screens to be │
│ │ moved. The screens are moved in proper order. │
│ │ The starting and ending source and destination │
│ │ screens are displayed and a response of Y is │
│ │ required before the copy will proceed. Any │
│ │ other response will abort the copy. │
└───────────────────┴──────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────┐
│ Control keys active in the Edit mode │
├───────────┬──────────────────────────────────────────────────────────┤
│ │ │
│ [up] │ up-arrow, moves cursor up one line │
│ [down] │ down-arrow, moves the cursor down one line │
│ [left] │ left-arrow, moves the cursor left one character │
│ [right] │ right-arrow, moves the cursor right one character │
│ [home] │ Home-key, moves the cursor to screen top-left │
│ [away] │ End-key, moves the cursor to bottom-right - 8 spaces │
│ [tab] │ Tab-key, moves the cursor to the next tab-right │
│ [back] │ shift-Tab-key, tabs the cursor left │
│ [I/C] │ Ins-key, inserts a space at the cursor │
│ [D/C] │ Del-key, deletes the character at the cursor │
│ [I/L] │ F7-key, inserts 64 spaces starting at the cursor │
│ [D/L] │ F8-key, deletes 64 characters from the cursor │
│ [clear] │ F9-key, clears the screen from the cursor │
│ │ to the [away] position, leaves the │
│ │ cursor at the [away] position │
│ [abandon] │ ^Q-keys, exits the Edit mode without updating │
│ │ the disk │
│ [confirm] │ ^E-keys, exits the Edit mode and updates the │
│ │ disk. │
└───────────┴──────────────────────────────────────────────────────────┘
┌──────────────────────────────────┐
│ Assembler Documentation │
└──────────────────────────────────┘
The assembler is invoked by typing: CODE, followed by
the name of the new code word; the assembler instructions
are typed next, and the definition is terminated by typing
"NEXT,END-CODE". The following example illustrates this.
CODE ONE ( --1 ) 1 # 0 MOV, 0 PUSH, NEXT, END-CODE
┌─────────────────────────────────────┐
│ Format: source destination OPCODE, │
└─────────────────────────────────────┘
┌───────────────────┐
│ Registers: │
├───────────────┬───┴────────┬────────────┬───────────────┐
│ 0 = AX │ 1 = CX │ 2 = DX │ 3 = BX = W │
├───────────────┼────────────┼────────────┼───────────────┤
│ 4 = SP = S │ 5 = BP = R │ 6 = SI = I │ 7 = DI = U * │
└───────────────┴────────────┴────────────┴───────────────┘
┌──────────────────────────────────────────────────────┐
│ [BX] = W ) = 3 ) [BX+SI] = W I + ) ** │
│ [BP] = R ) = 5 ) [BX+DI] = W U + ) │
│ [SI] = I ) = 6 ) [BP+SI] = R I + ) │
│ [DI] = U ) = 7 ) [BP+DI] = R U + ) │
└──────────────────────────────────────────────────────┘
** or W ) I ) + or 3 6 + ) or 3 ) 6 ) + or 9 ) etc.
ie: registers are treated as numbers by the opcodes
* U is a memory location in the present version of FORTH
┌────────────────────────────────────────────────────────┐
│ [reg+disp] = disp reg) ie: n r) or 3 W │
│ [reg+reg+disp] = disp reg) reg) + ie: n W) I) + │
└────────────────────────────────────────────────────────┘
As in other FORTH operations, the rule is: parameters
first, operators next, where W, R, I, and U are parameters
and ) is an operator; and disp is a parameter and reg) is an
operator. Note that the ) and reg) operators are
commutative under addition.
┌──────────────────────────────────────────────────────┐
│ Operators │
├──────────────────────────────────────────────────────┤
│ ) = register indirect │
│ reg) = register indirect + displacement │
│ # = immediate │
│ #A = address │
│ BYTE = set byte mode (default is WORD) │
│ L = low byte (applies to registers) │
│ H = high byte (as above) │
│ (CL) = shift/rotate by number in reg 1 = CL │
│ (DX) = IN or OUT address in reg 2 = DX │
│ (ex: n IN, or DX IN,) │
│ REL = relative CALL, or JMP, │
│ FAR = intersegment CALL, or JMP, │
│ CS SS DS ES = segment reg operators │
└──────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ Examples │
├──────────────────────────────────────────────────────────┤
│ 1 2 ADD, CX + DX -> DX │
│ 0 U ) CMP, [DI] - AX -> flags │
│ W U + ) 6 TEST, SI - [BX+DI] -> flags │
│ 0 10 W) ADC, AX + [BX+10] + cy -> [BX+10] │
│ 5 W) U) + 2 AND, [BX+DI+5] and DX -> DX │
│ PAD #A 0 OR, PAD or AX -> AX │
│ 2 TIB #A SUB, TIB - DX -> TIB │
│ 80 # 0 XOR, 80 xor AX -> AX │
│ -1 # W ) MOV, -1 -> [BX] │
│ "400 # 10 U) MOV, 1024 -> [DI+10] │
│ 30 # HERE #A ADD, 30 + (HERE) -> HERE │
│ ES 0 3 U) MOV, AX -> [DI+3] (+[ES] vs [DS]) │
│ segment offset FAR JMP, goto new seg+offs │
│ address REL JMP, jump to address │
│ FORTH Documentation │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────┐
│ File Name: ██ forth2.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ The FORTH Processor ║
║ ║
║ by ║
║ ║
║ Guy Kelly ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Editor's Note │
└──────────────────────────────────┘
The 83 Standard PC-FORTH executable module, FORTH.OBJ,
is contained on Diskette B. It is a public-domain FORTH
designed by Mr. Guy Kelly, and the source code is available
from:
╔════════════════════════════════╗
║ Guy M. Kelly ║
║ 2507 Caminito La Paz ║
║ La Jolla, CA 92037 ║
╚════════════════════════════════╝
Send $25.00 for 2 diskettes and handling, or copy a
friend's diskette containing the source code.
Another public domain FORTH is F-83, by Laxen and
Perry. It is available from:
╔════════════════════════════════╗
║ No Visible Support Software ║
║ P.O. Box 1344 ║
║ 2000 Center Street ║
║ Berkeley, CA 94794 ║
╚════════════════════════════════╝
Send $25.00, specify: 8080 C/PM-80 model (8" disks)
8086 C/PM-86 model (8" disks)
8086 MS-DOS model (5.25" disks)
┌──────────────────────────────────┐
│ Overview │
└──────────────────────────────────┘
On Diskette B of PCFL/PCUG, I have included a working
FORTH processor, FORTH.OBJ. This is an executable module,
despite the "OBJ" file extension (do not attempt to LINK or
run it under DOS!)
In future columns, I explain how to use FORTH.OBJ, but
reference documentation is provided in this month's FORTH
column. (See the "FORTH Reference Documents" article.)
FORTH.OBJ is the 83 Standard PC-FORTH, and you can use
it to test examples presented in this column, and to further
your knowledge of FORTH.
┌──────────────────────────────────┐
│ File Overview │
└──────────────────────────────────┘
The following files on Diskette B, can be used to
create a self-booting FORTH diskette:
1. FORTH.OBJ is the self-booting FORTH. It needs to
reside on the first seven tracks of a single-sided diskette.
2. FORTH.BAT is a batch file to help put it there.
3. FORTH.MSG contains instructions, displayed from
FORTH.BAT.
┌──────────────────────────────────┐
│ Self-booting FORTH │
└──────────────────────────────────┘
To create a self-booting FORTH diskette on drive A,
proceed as follows:
Insert a diskette containing DEBUG (the program
DEBUG.EXE) into drive A.
The diskette on drive B should contain the three FORTH
files mentioned above.
Type A>B:FORTH
press the Enter key, and follow the instructions.
The result is a self-booting FORTH diskette in drive A.
(EDITOR'S NOTE: Magic!)
┌──────────────────────────────────┐
│ File Name: ██ forth3.txt ██ │
└──────────────────────────────────┘
╔═════════════════════════════════════════════════════════════════════════╗
║ <<<< Disk No: 160 PC Firing Issue #2 >>>> ║
╠═════════════════════════════════════════════════════════════════════════╣
║ ║
║ To start this disk, type: ║
║ ║
║ PCFL (press enter) ║
║ ║
╚═════════════════════════════════════════════════════════════════════════╝
Copyright 1984 by ABComputing May 15, 1984
┌────────────────────┐
│ KEDIT Review │
┌────────────────────────────────────────────────────────────────────┐
│ │
│ Reviewed by: Bill Salkin │
│ │
│ Product Name: KEDIT │
│ Description: Full screen text editor with limited word- │
│ processing capabilities. │
│ │
│ Overall Rating: Excellent │
│ │
│ Company: Mansfield Software Group │
│ P.O. Box 532, Storrs, CT 06268 │
│ (203) 429-8402 │
│ │
│ Version: 3.0 │
│ Price: $95 + $3 shipping │
│ Copy Protected: No │
│ RAM Needed: 160K │
└────────────────────────────────────────────────────────────────────┘
┌────────────────────┐
│ KEDIT Review │
┌────────────────────────────────────────────────────────────────────┐
│ │
│ DOS Level: 1.0, 1.1, or 2.0 │
│ Monitor(s): Monochrome or Color │
│ │
│ Manual: Xeroxed. Highly readable with good tutorials. │
│ │
│ Unusual 1. Max. 15 files can be in memory for editing │
│ Features: 2. Screen can be split into multiple windows │
│ 3. Integral SORT command │
│ 4. Supports DOS 2.0 directory structure, and │
│ Path command │
│ 5. Includes useful word-processing features │
│ 6. Keyboard keys are user definable │
│ 7. Logical operators accepted in search operations │
│ 8. Disk directory can be called up in a file │
│ 9. Can recover up to last 12 changes made to file │
└────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────┐
│ Introduction │
└──────────────────────────────────┘
KEDIT is designed to be similar to XEDIT - the IBM
mainframe editor. (But, KEDIT does not have a "prefix"
area.) Text-editing and word-processing features are
combined to create a fast, powerful, and versatile product
that is superior to IBM's Personal Editor in almost all
respects. (Note: KEDIT edits files completely in memory; no
disk spill facility is available as with the Personal
Editor.)
A DEMO copy of KEDIT can be purchased from Mansfield
Software for $10.
┌──────────────────────────────────┐
│ The KEDIT Screen │
└──────────────────────────────────┘
When a new file, new1, is edited using KEDIT, the
screen looks like:
┌────────────────────────────────────────────────────────────────────┐
│ file d:new1 line=0 column=1 size=0 memory=81K │
│ new file... │
│ │
│ │
│ │
│ ***tof*** │
│ ***eof*** │
│ │
│ │
│ │
│ ====>_ │
└────────────────────────────────────────────────────────────────────┘
The status line at the top of the screen indicates: the
file being edited ("new1"), the line ("0") and column number
("1") the cursor is on, the number of lines in the file
("0"), and the amount of RAM available ("81K").
The message line, displaying the phrase "new file,"
reports error and informational messages.
Let's customize the screen layout...
The "command" line is marked with an arrow, but I
prefer the traditional reverse video command line. (Can't
teach an old dog new tricks.) Typing "arrow off" on the
command line makes the arrow disappear, and using the
"attribute" command generates a reverse video command line.
The screen looks like:
┌────────────────────────────────────────────────────────────────────┐
│ file d:new1 line=0 column=1 size=0 memory=81K │
│ │
│ │
│ │
│ ***tof*** │
│ ***eof*** │
│ │
│ │
│ │
│ ██████████████████████████████████████████████████████████████████ │
└────────────────────────────────────────────────────────────────────┘
The "tof" (top-of-file) marker appears on the current
line, which is normally in the middle of the screen. I
prefer the "tof" marker to appear at line 3 (the top of the
screen), so I make the top of the screen the current line by
using the command "set curline 3".
Continuing in this spirit, let's split the screen into
two horizontal screens, with the top screen split vertically
into two screens. Typing "screen 12 v 13" on the command
line and pressing Enter does the trick. The top screen
consists of 12 lines and the bottom 13 lines. The "v"
indicates that the top screen is to be split vertically.
These screens are not visually shown until files are
edited requiring their use. To activate these screens, type
"k new2", press Enter, type "k new3", and press Enter. ("K
new2" causes KEDIT to edit, or create, the file new2.)
After these commands are issued, the screen looks like:
┌────────────────────────────────────────────────────────────────────┐
│ file d:new1 line= column= ││file d:new2 line= column= │
│ ││ │
│ ***tof*** ││ ***tof*** │
│ ***eof*** ││ ***eof*** │
│ ││ │
│ ││ │
│ ││ │
│ ██████████████████████████████ ││ ████████████████████████████████ │
│ file d:new3 line=0 column=1 size=0 memory=81K │
│ │
│ ***tof*** │
│ ***eof*** │
│ │
│ │
│ │
│ │
│ ██████████████████████████████████████████████████████████████████ │
└────────────────────────────────────────────────────────────────────┘
Files new1, new2, and new3 are now in memory. The
"line" and "column" fields are blanked in files new1, and
new2 because neither file is currently being edited. File
new3 is currently being edited as shown by the presence of
numbers in the status line.
This is just a taste of the fun you can have with
KEDIT. And better yet, the file PROFILE.KED can be used to
save all of the commands we typed, so when KEDIT is invoked,
I am greeted by the silver screen I desire.
┌──────────────────────────────────┐
│ The Current Line │
└──────────────────────────────────┘
KEDIT uses the current line as a reference or anchor
point for many commands.
1. For example, typing /HELLO/ on the command line will
cause KEDIT to search each line in the file, from the line
after the current line, until HELLO is found. If a line
containing HELLO is found, this line becomes the current
line.
2. As another example, the SORT instruction (an integral
part of KEDIT)
SORT *
causes all lines from the current line to the bottom of the
file, to be sorted into ascending order (using the current
"zone" settings to define the area to be sorted).
┌──────────────────────────────────┐
│ Key Definition Primitives │
└──────────────────────────────────┘
Function keys and key combinations can be redefined
using a rich collection of primitives.
As a simple example,
def home [TOPEdge][LEFTEdge]
is used to define the HOME key to move the cursor to the top
edge of the screen, and then to the leftmost edge. The
capitalized letters indicate the minimal characters that
must be typed for this command to be recognized.
The next example defines the F1 key as follows: if the
cursor is on the command line, execute the command;
otherwise, move the cursor to the left margin on the next
line.
def F1 [IFcommand][ex][ELSE][cdn][marginl][ENDIF]
This is a little crowded, but I hope you notice the
presence of the "IF..ELSE..ENDIF" structure. I have not yet
used this feature extensively, but it sure looks
interesting!
┌──────────────────────────────────┐
│ Block Commands Supported │
└──────────────────────────────────┘
KEDIT supports three types of "blocking." "Line"
blocking is used in preparation for deleting, moving, or
copying a line or group of lines.
"Box" blocking is useful for overlaying text in boxes
to create artwork. "Box" blocking and overlaying operate in
the same manner as in the Personal Editor reviewed in the
first issue of PCFL/PCUG.
"Stream" blocking could be called character-blocking.
Sentence fragments, such as from the "third word on line
three, to the fourth word on the fourth line," can be
stream-blocked and then moved, copied, or deleted.
┌──────────────────────────────────┐
│ Targets │
└──────────────────────────────────┘
To "pick" out locations in a file, KEDIT is given a
target.
┌──────────────────────────────────┐
│ Absolute Line Number Targets │
└──────────────────────────────────┘
To make line 8 in the file the current line, type
:8
┌──────────────────────────────────┐
│ Relative Line Number Targets │
└──────────────────────────────────┘
To make the line 8 lines below the current line, the
current line, type
8
Typing -3 would make the line 3 lines above the current
line the new current line.
┌──────────────────────────────────┐
│ String Targets │
└──────────────────────────────────┘
Typing /HELLO/ on the command line causes KEDIT to
search each line in the file, from the line after the
current line, until it finds the word HELLO. This line is
then made the current line.
Typing
/HELLO/ & /GOODBYE/
will cause KEDIT to search for the next line containing
HELLO and GOODBYE. That is, KEDIT supports logical
operations in target searches.
┌──────────────────────────────────┐
│ Named Line Targets │
└──────────────────────────────────┘
Have you ever been on line 352 in a file, gone to the
top of the file, and then pressed PgDn until you came to
line 253, or was it 523, or 352?
In KEDIT, a line is assigned a "name" using the "POINT"
command. (This label is not part of the file - it is active
only while the file is edited.) You may go to any line in
the file, type the "name" of a line on the command line (or
assign the equivalent function to a function key), and KEDIT
will make the named line the current line. In short, KEDIT
recognizes individual lines and can "goto" them.
┌──────────────────────────────────┐
│ Commands Allowing Targets │
└──────────────────────────────────┘
Commands accepting targets can also specify whether the
command affects the current "block," "paragraph," or the
entire file.
The command "uppercase 4" will capitalize all letters,
starting with the current line, and the next three lines.
If an area is "box blocked", "uppercase block" will
capitalize all letters in the block.
"Uppercase ALL" capitalizes all letters from the
current line to the end of the file.
┌──────────────────────────────────┐
│ KEDIT Commands │
└──────────────────────────────────┘
A few KEDIT commands deserve special mention. Others
are listed in a table.
1. A powerful sort command is an integral part of KEDIT.
Unlike DOS 2.0, which can sort a maximum of 64K data, KEDIT
"cannot sort more than 8000 lines, regardless of how much
memory is available." (Quote from the user's manual.)
The command
SORT 6 A 4 5 1 3
tells KEDIT to sort 6 lines, starting with the current line,
in ascending order, sorting on the data in columns 4 and 5,
and then columns 1 through 3.
2. Typing an equal sign on the command line causes the
last command issued to be re-issued.
3. Preceding a command by an ampersand, as in "&dir",
causes the command to remain on the command line
indefinitely after execution. The command may then be
re-executed by pressing the Enter key.
Other KEDIT commands are shown below.
┌─────────────────────────────────────┬───────────────────────────────────────┐
│ Example │ Function │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ change /this/that/ * * │ Changes all occurrences of "this" │
│ │ to "that" from current line to end │
│ │ of file. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ def c-F1 │ Defines ctrl-F1 key. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ dir [D:] │ Directory on drive D. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ fileid new │ Changes filespec to "new." │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ getfile fileid (fromline) │ Adds lines from disk file to the │
│ (forlines) │ file you are editing. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ query tabs │ Causes display of tabs in message │
│ │ area. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ quit │ Exits a file if no changes made to │
│ │ it. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ qquit │ Exits a changed file. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ schange /A/B/ │ Selective change - asks if you │
│ │ want to make the change. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ status │ Display value of each SET option. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ ? │ Causes the last command issued to │
│ │ be redisplayed on the command line. │
└─────────────────────────────────────┴───────────────────────────────────────┘
┌──────────────────────────────────┐
│ Set Commands │
└──────────────────────────────────┘
"Set" commands are used by KEDIT for a variety of
functions such as adjusting the margins, turning wordwrap on
or off, setting attributes, using the DOS 2.0 path command,
and creating a "lineend" character to separate multiple
commands.
Typing the command
SET MARGINS 11 70 16
on the command line establishes the left margin at column
11, the right margin at column 70, and the paragraph
indentation at column 16.
The word set is optional in all set commands, and the
above command could have been typed:
MARGINS 11 70 16
The command
SET ARBchar ON $ ?
assigns special meaning to the characters "$" and "?' when
used in string targets and with the change and schange
commands. The ARBchar characters act as wildcards. (The
parallel concept under DOS is the wildcard character "*", as
in erase *.* .)
The command
SET attributes n1 n2 n3...
is used to adjust the attributes of: normal text, the
current line, text within blocks, text within a block when
the line involved is also the current line, the command
line, the status line, the message line, the arrow, line
numbers (with NUMBER ON), the scale and tab lines, target
lines, and target lines that are also the current line.
(There is enough flexibility here to meet any taste.)
Other Set commands are shown in the following table.
┌─────────────────────────────────────┬───────────────────────────────────────┐
│ Example │ Function │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ set case Mixed Respect │ Upper/lower case accepted as │
│ │ input; cases must match in change │
│ │ and schange commands. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ set cmdline Top │ Positions the command line at the │
│ │ top of the screen. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ set curline 3 │ Make the third line on the screen │
│ │ the current line. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ set dbase on │ Causes file to be written to disks │
│ │ in 512 byte multiples; required by │
│ │ dBASE II, version 2.4. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ set justify on │ Paragraphs are justified during │
│ │ formatting. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ set margins 11 70 17 │ Set left margin to column 11; │
│ │ right margin to column 70; in- │
│ │ dentation to column 17 │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ set number on │ Causes line #'s to be displayed. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ set path on │ Causes KEDIT and GETFILE commands │
│ │ to search for files in directories │
│ │ defined by DOS PATH command. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ set screen n1(v) n2(v) n3(v) n4(v) │ Sets size and number of windows │
│ │ displayed on screen. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ set tabsout on │ Causes blank compression when file │
│ │ saved. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ set tabsin on │ Expands tabs in input files. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ set varblank on │ Controls how multiple blanks are │
│ │ controlled in string searches. │
├─────────────────────────────────────┼───────────────────────────────────────┤
│ set wordwrap on │ Enables wordwrap feature. │
└─────────────────────────────────────┴───────────────────────────────────────┘
┌──────────────────────────────────┐
│ Word Processing Features │
└──────────────────────────────────┘
┌────────────────────────────┬────────────────────────────────────────────────┐
│ Example │ Function │
├────────────────────────────┼────────────────────────────────────────────────┤
│ ctrl-c │ Centers a line on the screen. │
├────────────────────────────┼────────────────────────────────────────────────┤
│ ctrl-l │ Left adjust a line within the margin │
│ │ settings. │
├────────────────────────────┼────────────────────────────────────────────────┤
│ ctrl-f │ If JUSTIFY is on, and ctrl-f (for format) │
│ │ is pressed, paragraphs will be justified │
│ │ between the bounds set by the margin │
│ │ command. │
├────────────────────────────┼────────────────────────────────────────────────┤
│ ctrl-r │ Right adjust a line within the margin │
│ │ settings. │
└────────────────────────────┴────────────────────────────────────────────────┘
Ctrl-r is very useful for placing dates at the top of a
letter. Simply type the date in the left column, press
ctrl-r, and the last character of the date is shifted to the
right margin established by the margin command.
A nice feature of KEDIT is that paragraphs are
separated by blank lines. This may seem a small point, but
it is a very convenient one. (Certain word processors use a
special symbol to denote the end of a paragraph. Typical
scenario: while editing a file, you fail to use the end of
paragraph marker and reformat a paragraph - the remainder of
the file is justified! One hunk of tangled mess results,
and there is no way of undoing this. This problem is
avoided by defining a paragraph as is done in KEDIT.)
┌──────────────────────────────────┐
│ Manual │
└──────────────────────────────────┘
I enjoyed reading the manual that came with this
product. It is well organized and contains excellent
tutorials that are explicit and mercifully brief.
The manual is xeroxed, but highly readable.
┌──────────────────────────────────┐
│ Conclusion │
└──────────────────────────────────┘
KEDIT is the editor I use in my daily work. It is
extremely fast, powerful, flexible, and its word-processing
features are convenient to use.
I suggest you give it a try.
┌──────────────────────────────────┐
│ File Name: ██ kedit.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by Gary M. Rader May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ Converting Infix to Prefix Notation ║
║ ║
║ by ║
║ ║
║ Gary M. Rader ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Introduction │
└──────────────────────────────────┘
Suppose we are designing a spreadsheet or calculator in
which the user can enter expressions like
(A3 + A4 - 2 * A10)
or
(365 + (4777 - 1330) * 12)
Such expressions are in "infix" form because the
operators are positioned between their operands rather than
positioned before ("prefix"), or after ("postfix") them.
┌──────────────────────────────────┐
│ LISP uses Prefix Form │
└──────────────────────────────────┘
LISP can only directly evaluate expressions in prefix
form, where the operator is positioned before its operands.
For example, instead of (10 + 20), LISP requires (+ 10 20).
In order for LISP programs to evaluate expressions like
those above, the expressions must first be converted to
prefix notation so they look like
(- (+ A3 A4) (* 2 A10))
and
(+ 365 (* (- 4777 1330) 12))
respectively.
Notice that infix notation is basically limited to
binary operators - operations which take two operands like
+, -, *, /, MOD, >, =, <, ~ (boolean "not"), & (boolean
"and"), and | (boolean "or"). Operations requiring, say,
three operands, like the present value function, cannot use
infix notation. Thus it appears in many spreadsheets
looking something like
@PV(Payment, Interest Rate, Term)
which is a form of prefix notation. Life would be much
easier for both humans and computers if we all forgot about
infix notation. Unfortunately, the use of infix notation,
for the operators listed above, has become too deeply rooted
in our culture to easily change. We continue to use a
hybrid of infix and prefix notation in much of our
mathematics.
┌──────────────────────────────────┐
│ "InfixToPrefix" Program │
└──────────────────────────────────┘
The program "IToP" (standing for "InfixToPrefix") takes
a single argument, in infix form, and converts it to prefix
form. (IToP resides in the program file accompanying this
article. It is written in muLISP-83.) This output prefix
form will be in the form of a list.
For instance,
(IToP '(10 - 9 * 8))
returns the list
(DIFFERENCE 10 (TIMES 9 8))
as its result. (DIFFERENCE is the LISP name for
subtraction. TIMES is the LISP name for multiplication.)
You will notice that a number of associated functions
are also defined in that file. The function "IToPHelp" is a
help function for IToP. "GetOperands" is a help function
for IToPHelp. The conversion program is set up so you can
define new operators without fussing with any function
definitions. Two operator-defining functions are defined,
one for infix operators ("DefInfixOp"), and one for prefix
operators ("DefPrefixOp").
DefInfixOp has the form
(DefInfixOp <symbol> <LISP function> <precedence>)
where
<symbol> is the symbol for the operator
<LISP function> is the muLISP function associated with the
operator
and
<precedence> is the operator's precedence.
(Precedence is what makes "(1 * 2 + 3)" equal "((1 * 2)
+ 3)" rather than "(1 * (2 + 3))". In this case "+" has a
higher precedence than "*".)
For example, to define binary "+" as the muLISP
function PLUS with a precedence of 3, type
(DefInfixOp '+ 'PLUS 3)
DefPrefixOp has the form
(DefPrefixOp <symbol> <LISP function> <arity> <minimum arity>)
where the first two input parameters are as before and the
last two deal with the number of operands. If <arity> is
specified, then the function is required to have exactly
that many operands. If <arity> is not specified, the
minimum number of operands allowable in the function must be
specified. All prefix operators have a precedence of 1,
automatically.
To define unary "-", we type
(DefPrefixOp '- 'MINUS 1)
To define the function SUM, which takes two or more
operands and returns their sum, we type
(DefPrefixOp 'SUM 'PLUS NIL 2)
Note that the LISP function in these definitions can be
a user-defined function.
Using the operator definitions in the corresponding
program file, the following conversions occur (the input is
not indented, the result is):
(10 - 9)
(DIFFERENCE 10 9)
(10 - - 9)
(DIFFERENCE 10 (MINUS 9))
(10 + 9 * 8 - - A > 3 / B)
(GREATERP (DIFFERENCE (PLUS 10 (TIMES 9 8)) (MINUS A))
(QUOTIENT 3 B))
(5 + (SUM A (3 * (B MOD 2)) 365) = (C * (747 + D)))
(EQUAL (PLUS 5 (PLUS A (TIMES 3 (REMAINDER B 2)) 365))
(TIMES C (PLUS 747 D)))
Some error checking is performed in the program.
However, it is not exhaustive. When an error is
encountered, the speaker beeps and the conversion
terminates. This action can be altered by changing the
"(PRIN1 (ASCII 7))" parts of all "(THROW 'Error ...)"
statements to the desired action.
Finally, the following code evaluates any infix
expression "Exp."
(EVAL (IToP Exp))
e.g.,
(EVAL (IToP '(10 + 9)))
19
or
(SETQ Exp '(10 + 9 * 8 - - 7))
(EVAL (IToP Exp))
89
In conclusion, IToP is a muLISP-83 function which
converts infix arithmetic expressions into prefix form
suitable for evaluation by muLISP's EVAL function. Such a
function is useful in both spreadsheet programs and
calculator programs where the user enters expressions or
formulas in infix notation. New infix and prefix operators
can be defined using DefInfixOp and DefPrefixOp.
┌──────────────────────────────────┐
│ LISP News │
└──────────────────────────────────┘
LISP/88 which was mentioned in last issue's LISP
article seems to work relatively well. At $49.95 it is the
cheapest implementation of LISP available for the IBM-PC. I
recommend it for those wanting to learn LISP, but not for
serious LISP software development.
Several new LISPs are about. The LISP Company has TLC
LISP while Gold Hill Computers announced Golden Common LISP
(GCLISP). A review of muLISP, IQLISP, and TLC LISP appears
in the April, 1984, issue of PC Tech Journal.
Unfortunately, muLISP-82 was used, instead of muLISP-83,
making the review fairly worthless for determining which
LISP is most suitable for a particular application.
However, it does give a good indication of the differences
between IQLISP and TLC LISP.
An excellent new book for learning LISP is available:
"LISP: A Gentle Introduction to Symbolic Computation" by
David S. Touretzky, Harper & Row, 1984, $18.95.
┌────────────────────────────────────────────────────────────────────────┐
│ LISPs Mentioned in This Article │
├─────────────────────────────────────┬──────────────────────────────────┤
│ Golden Common LISP (GCLISP) │ IQLISP │
│ $375 │ $175 │
│ Gold Hill Computers │ Integral Quality │
│ 163 Harvard St. │ P.O. Box 31970 │
│ Cambridge, MA 02139 │ Seattle, WA 98103-0070 │
│ (617)492-2071 │ (206)527-2918 │
├─────────────────────────────────────┼──────────────────────────────────┤
│ LISP/88 │ muLISP-83 │
│ $49.95 │ $250 │
│ Norell Data Systems │ The Soft Warehouse │
│ 3400 Wilshire Blvd. │ P.O. Box 11174 │
│ P.O. Box 70127 │ Honolulu, Hawaii 96828-0174 │
│ Los Angeles, CA 90010 │ (808)734-5801 │
│ (213)257-2026 │ │
├─────────────────────────────────────┼──────────────────────────────────┤
│ TLC LISP │ │
│ Price Unavailable │ │
│ The LISP Company │ │
│ 330 C Village Lane │ │
│ Los Gatos, CA 95030 │ │
│ (408)354-3668 │ │
└─────────────────────────────────────┴──────────────────────────────────┘
┌──────────────────────────────────┐
│ File Name: ██ lisp1.txt ██ │
└──────────────────────────────────┘
;Copyright 1984 by ABComputing May 15, 1984
;
; ┌───────────────────────────────────────────────────────────────────┐
; │ │
; │ THIS FILE CONTAINS FIVE ROUTINES: │
; │ │
; │ KEYS - INDICATES IF A PRESSED KEY GENERATES AN │
; │ EXTENDED OR NON-EXTENDED ASCII CODE. │
; │ DRIVE - CHANGES DEFAULT DRIVE TO "B: DRIVE. │
; │ CURSOR - MOVES CURSOR TO HOME POSITION │
; │ REVERSE - MANIPULATES STRING "CBA" INTO "ABC". │
; │ RENAM - RENAMES THE FILE "A:TEMP.TXT" TO "A:TRASH.TXT". │
; │ │
; │ EACH ROUTINE SHOULD ASSEMBLE AND LINK WITHOUT WARNINGS OR │
; │ ERRORS. │
; │ │
; │ DOS CALLS ARE LISTED IN THE APPENDIX OF THE DOS MANUAL. FOR │
; │ BIOS CALLS, OBTAIN EITHER THE TECH. REF. MANUAL, OR REVIEW │
; │ THE "INTERRUPT PHONEBOOK" IN THE DOS COLUMN OF OUR FIRST │
; │ ISSUE. │
; │ │
; └───────────────────────────────────────────────────────────────────┘
;Copyright 1984 by ABComputing May 15, 1984
; ┌───────────────────────────────────────────────────────────────────┐
; │ │
; │ EACH KEY ON THE KEYBOARD, WHEN PRESSED, GENERATES EITHER AN │
; │ ASCII CODE, OR AN EXTENDED-ASCII CODE. (SEE APPENDIX IN THE │
; │ BASIC MANUAL FOR DETAILED LISTINGS OF SCAN CODES.) THIS │
; │ ROUTINE USES THE BIOS INT 16H TO READ THE KEYBOARD AND RETURN │
; │ THESE SCAN CODES. │
; │ │
; │ AFTER A KEY IS PRESSED, IF AL = 0 THEN AN EXTENDED-SCAN-CODE │
; │ KEY WAS PRESSED,AND THE SCAN CODE OF THE KEY IS RETURNED IN │
; │ AH. IF AL<> 0, THEN AL CONTAINS THE SCAN CODE FOR THE KEY. │
; │ │
; │ THIS ROUTINE PRINTS A MESSAGE INDICATING THE TYPE OF SCAN │
; │ CODE GENERATED. EITHER: "A NON-EXTENDED-SCAN-CODE KEY WAS │
; │ PRESSED" OR "AN EXTENDED-SCAN-CODE KEY WAS PRESSED". │
; │ │
; │ PRESS F10 TO EXIT THIS ROUTINE. F10 HAS AN EXTENDED-SCAN │
; │ CODE OF 68 │
; │ │
; │ PLACE THIS ROUTINE IN FILE: KEYBOARD.ASM │
; │ │
; └───────────────────────────────────────────────────────────────────┘
;
;
;--THINK OF "EQU" AS AN "EQUATE" OR EQUAL SIGN. THE ASSEMBLER
; WILL REPLACE EACH OCCURRENCE OF "CR", AND "LF" IN THE SOURCE
; CODE BY 10 AND 13, RESPECTIVELY.
;
CR EQU 10
LF EQU 13
F10 EQU 68 ;SCAN CODE FOR F10 IS 68 (SEE BASIC APPENDIX)
;------------------------------------------------------------------------
DATA SEGMENT PARA
ANY_KEY DB 'PRESS ANY KEY',CR,LF,'$'
NORMAL_KEY DB 'A NON-EXTENDED-SCAN-CODE KEY WAS PRESSED'
DB CR,LF,CR,LF,'$'
EXTENDED_KEY DB 'AN EXTENDED-SCAN-CODE KEY WAS PRESSED'
DB CR,LF,CR,LF,'$'
DATA ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
STACK SEGMENT PARA STACK 'STACK'
DB 40H DUP('STCK')
STACK ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
CODE SEGMENT PARA
ASSUME CS:CODE, DS:DATA, SS:STACK
;--STANDARD LINKAGE TO DOS
KEYS PROC FAR ;DO
PUSH DS ;
SUB AX,AX ;
PUSH AX ; NOT
MOV AX,DATA ;
MOV DS,AX ; ALTER!
;--PRINT "PRESS ANY KEY" MESSAGE
KEY0: MOV AH,9 ;REQUEST "DISPLAY STRING" SERVICE
MOV DX,OFFSET ANY_KEY ;DS:DX -> ANY_KEY
INT 21H ;INVOKE "DISPLAY STRING" SERVICE
;--WAIT FOR KEYBOARD INPUT.
MOV AH,0
INT 16H
;--AL = 0 MEANS AN EXTENDED-SCAN-CODE KEY.
CMP AL,0 ;CoMPare CONTENTS OF AL TO 0
JE KEY1 ;IF AL = 0, THEN JUMP OR BRANCH TO
; THE LABEL KEY1.
;--NORMAL SCAN CODE KEY PRESSED
MOV DX,OFFSET NORMAL_KEY ;DS:DX -> NORMAL_KEY
JMP KEY2
;--EXTENDED-SCAN-CODE KEY PRESSED. WAS IT F10 TO EXIT TO DOS?
KEY1: CMP AH,F10 ;WAS THE F10 KEY PRESSED?
JE KEY3 ;EQUALITY MEANS F10 PRESSED.
; BRANCH TO EXIT (KEY3).
;--PROCESS OTHER EXTENDED-SCAN-CODE KEYS.
MOV DX,OFFSET EXTENDED_KEY ;DS:DX -> EXTENDED_KEY
;--PRINT THE STRING POINTED TO BY DS:DX.
KEY2: MOV AH,9 ;REQUEST "DISPLAY STRING" SERVICE
INT 21H ;INVOKE "DISPLAY STRING" SERVICE
JMP KEY0 ;LOOP FOR NEXT KEYIN
;-- RETURN TO DOS
KEY3: RET ;RETurn to DOS
KEYS ENDP ;END of PROCedure
CODE ENDS ;END of CODE Segment
;------------------------------------------------------------------------
END KEYS ;END of routine KEYS
;Copyright 1984 by ABComputing May 15, 1984
;
; ┌───────────────────────────────────────────────────────────────────┐
; │ │
; │ DOS FUNCTION CALL 0EH (14 DECIMAL) IS USED TO: 1) CHANGE THE │
; │ DEFAULT DRIVE TO B, AND 2) RETURN THE NUMBER OF DISK DRIVES │
; │ (INCLUDING FIXED DISK) ON THE SYSTEM, IN AL. │
; │ │
; │ PLACE THIS ROUTINE IN FILE: DRIVE.ASM │
; │ │
; └───────────────────────────────────────────────────────────────────┘
;
;------------------------------------------------------------------------
;------------------------------------------------------------------------
DATA SEGMENT PARA
DATA ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
STACK SEGMENT PARA STACK 'STACK'
DB 40H DUP('STCK')
STACK ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
CODE SEGMENT PARA
ASSUME CS:CODE, DS:DATA, SS:STACK
;--STANDARD LINKAGE TO DOS
DRIVE PROC FAR ;DO
PUSH DS ;
SUB AX,AX ;
PUSH AX ; NOT
MOV AX,DATA ;
MOV DS,AX ; ALTER!
;--CHANGE CURRENT DRIVE TO B BY PLACING THE VALUE 1 (A = 0, B = 1,
; ETC.) IN DL. THE NUMBER OF DRIVES ON THE SYSTEMS IS RETURNED IN
; AL.
MOV DL,1 ;REQUEST B DRIVE
MOV AH,0EH ;REQUEST "SELECT DRIVE" SERVICE
INT 21H ;INVOKE "SELECT DRIVE" SERVICE
;------------------------------------------------------------------------
;
; MUST USE "0EH" INSTEAD OF "EH" FOR ASSEMBLER MIGHT CONFUSE "EH"
; WITH A LABEL (I.E. A NAME USED TO IDENTIFY A LOCATION IN SOURCE
; CODE. OFTEN USED AS A LOCATION TO BRANCH TO. "KEY0", "KEY1",
; AND "KEY2", IN ROUTINE KEYS.)
;
; A MORE CONFUSING SITUATION IS A MOV STATEMENT SUCH AS:
;
; MOV AH,AH ;MOVE AH CONTENTS INTO AH REGISTER!
;
;
; IF YOU WANT TO MOVE THE VALUE OF 10 INTO THE AH REGISTER, USE:
;
; MOV AH,0AH ;MOVE "0AH" = 10 HEX INTO AH REGISTER.
;
; OR
;
; MOV AH,10 ;10 IS INTERPRETED AS 10 DECIMAL.
;
;
; USE DEBUG TO STUDY THE VALUE IN THE AH REGISTER.
;
;------------------------------------------------------------------------
;-- RETURN TO DOS
RET ;RETurn to DOS
DRIVE ENDP ;END of PROCedure
CODE ENDS ;END of CODE Segment
;------------------------------------------------------------------------
END DRIVE ;END of routine DRIVE
;Copyright 1984 by ABComputing May 15, 1984
;
; ┌───────────────────────────────────────────────────────────────────┐
; │ │
; │ BIOS INTERRUPT 10H IS USED TO PLACE THE CURSOR AT THE UPPER │
; │ LEFT HAND CORNER OF THE SCREEN. │
; │ │
; │ THE SCREEN IS REGARDED AS BEING A GRID OF COORDINATES WITH │
; │ (0,0) AS THE UPPER LEFT CORNER, AND (24,79) AS THE LOWER │
; │ RIGHT CORNER. (24 = 24 DECIMAL.) │
; │ │
; │ PLACE THIS ROUTINE IN FILE: HOME.ASM │
; │ │
; └───────────────────────────────────────────────────────────────────┘
;
;------------------------------------------------------------------------
;------------------------------------------------------------------------
DATA SEGMENT PARA
DATA ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
STACK SEGMENT PARA STACK 'STACK'
DB 40H DUP('STCK')
STACK ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
CODE SEGMENT PARA
ASSUME CS:CODE, DS:DATA, SS:STACK
;--STANDARD LINKAGE TO DOS
CURSOR PROC FAR ;DO
PUSH DS ;
SUB AX,AX ;
PUSH AX ; NOT
MOV AX,DATA ;
MOV DS,AX ; ALTER!
;--INT 10H IS RESPONSIBLE FOR VIDEO/IO.
MOV AH,2 ;REQUEST "SET CURSOR" SERVICE
MOV DH,0 ;SET CURSOR ROW TO 0
MOV DL,0 ;SET CURSOR COLUMN TO 0
MOV BH,0 ;PAGE NUMBER = 0
INT 10H ;INVOKE "SET CURSOR" SERVICE
;-- RETURN TO DOS
RET ;RETurn to DOS
CURSOR ENDP ;END of PROCedure
CODE ENDS ;END of CODE Segment
;------------------------------------------------------------------------
END CURSOR ;END of routine CURSOR
;Copyright 1984 by ABComputing May 15, 1984
;
; ┌───────────────────────────────────────────────────────────────────┐
; │ │
; │ THIS ROUTINE MANIPULATES THE STRING "ABC" INTO "CBA" AND │
; │ DISPLAYS THE LATTER STRING. THIS ROUTINE ILLUSTRATES HOW TO │
; │ MANIPULATE A STRING IN MEMORY. │
; │ │
; │ PLACE THIS ROUTINE IN FILE: REVERSE.ASM │
; │ │
; └───────────────────────────────────────────────────────────────────┘
;
;------------------------------------------------------------------------
;------------------------------------------------------------------------
DATA SEGMENT PARA
MSG DB 'ABC'
BUFFER DB 0,0,0,'$' ;STORAGE FOR "CBA" STRING
DATA ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
STACK SEGMENT PARA STACK 'STACK'
DB 40H DUP('STCK')
STACK ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
CODE SEGMENT PARA 'CODE'
ASSUME CS:CODE,DS:DATA,SS:STACK
REVERSE PROC FAR ;STANDARD LINKAGE TO DOS
PUSH DS ; DO
SUB AX,AX ;
PUSH AX ; NOT
MOV AX,DATA ;
MOV DS,AX ; ALTER!
;------------------------------------------------------------------------
;
; "MSG" IS DEFINED IN OUR DATA SEGMENT AS:
;
;
; MSG DB 'ABC'
;
;
; "MSG" IS A LABEL IDENTIFYING A LOCATION IN MEMORY. AS SHOWN BELOW,
; "MSG" IS IDENTIFIED WITH THE CHARACTER "A" - THE FIRST BYTE OF
; "MSG".
;
; "MSG + 1" POINTS TO THE LOCATION ONE BYTE PAST "MSG". THIS
; CONTAINS THE CHARACTER "B".
;
; "MSG + 1" CAN EQUIVALENTLY BE WRITTEN MSG[1]; "MSG + 2" CAN BE
; WRITTEN MSG[2],ETC. THE ASSEMBLER WILL ACCEPT EITHER FORM.
;
;
;
; MSG MSG + 1 MSG + 2
; │ │ │
; "MSG" v v v
; ┌──────────────────────────────────┐
; │ A │ B │ C │
; └──────────────────────────────────┘
;
;
; OR
;
;
; MSG MSG[1] MSG[2]
; │ │ │
; v v v
; ┌──────────────────────────────────┐
; │ A │ B │ C │
; └──────────────────────────────────┘
;
;
; THIS ROUTINE MOVES THE THREE BYTES: MSG, MSG+1, MSG +2, INTO
; "BUFFER," A THREE BYTE AREA IN OUR DATA SEGMENT. THE CHARACTER "C"
; IS MOVED FIRST, THEN "B", THEN "A". "BUFFER" FINALLY LOOKS LIKE:
;
;
; BUFFER BUFFER + 1 BUFFER + 2
; │ │ │
; "BUFFER" v v v
; ┌──────────────────────────────────────────┐
; │ C │ B │ A │ $ │
; └──────────────────────────────────────────┘
;
;
; AS THE CONTENTS OF BUFFER WILL BE DISPLAYED, BUFFER IS TERMINATED
; BY A DOLLAR SIGN WHICH IS THE TERMINATOR FOR THE DOS PRINT STRING
; SERVICE.
;
;------------------------------------------------------------------------
MOV AL,MSG+2 ;AL = C
MOV BUFFER,AL ;BUFFER ->C
MOV AL,MSG+1 ;AL = B
MOV BUFFER+1,AL ;BUFFER +1 ->B
MOV AL,MSG ;AL = A
MOV BUFFER+2,AL ;BUFFER +2 ->A
;-- DISPLAY THE CONTENTS OF "BUFFER."
MOV DX,OFFSET BUFFER ;PUT THE ADDRESS OF BUFFER IN THE DX REGISTER
MOV AH,9 ;REQUEST "PRINT STRING" SERVICE
INT 21H ;INVOKE "PRINT STRING" SERVICE
;-- RETURN TO DOS
RET ;RETURN TO DOS
REVERSE ENDP ;END of PROCedure
CODE ENDS ;END of CODE Segment
;------------------------------------------------------------------------
END REVERSE ;END of routine REVERSE.
;Copyright 1984 by ABComputing May 15, 1984
;
; ┌───────────────────────────────────────────────────────────────────┐
; │ │
; │ THIS ROUTINE USES DOS CALL 17H TO RENAME THE FILE │
; │ "A:TEMP.TXT" TO "A:TRASH.TXT". │
; │ │
; │ AS THE RENAMED FILE IS ON SAME DRIVE AS THE ORIGINAL FILE, │
; │ THE FCB SPECIFIES THE NEW FILESPEC ONLY, NOT THE DRIVE OF THE │
; │ NEW FILE. (SEE THE ARTICLE "DOS 1.1, 2.0 SEQUENTIAL │
; │ FILE-READING" IN THIS MONTH'S ASSEMBLY COLUMN FOR AN │
; │ EXPLANATION OF WHAT AN FCB IS.) │
; │ │
; │ THIS ROUTINE SHOULD NOT BE NAMED "RENAME.ASM". FOR THE DOS │
; │ SYSTEM COMMAND "RENAME," WILL BE INVOKED WHEN WE TYPE RENAME │
; │ ON THE COMMAND LINE! (AND YOU THOUGHT THAT YOUR RENAME.EXE │
; │ MODULE WAS BEING EXECUTED!) │
; │ │
; │ PLACE THIS ROUTINE IN FILE: RENAM.ASM │
; │ │
; └───────────────────────────────────────────────────────────────────┘
;
;------------------------------------------------------------------------
DATA SEGMENT PARA
FCB_ADD DB 1,'TEMP ','TXT' ;CREATE ODD-BALL FCB WANTED
DB 5 DUP(' ') ; BY FUNCTION CALL 17H.
DB 'TRASH ','TXT' ;NEW NAME FOR FILE
DB 10 DUP('0')
DATA ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
STACK SEGMENT PARA STACK 'STACK'
DB 40H DUP('STCK')
STACK ENDS
;------------------------------------------------------------------------
;------------------------------------------------------------------------
CODE SEGMENT PARA 'CODE'
ASSUME CS:CODE,DS:DATA,SS:STACK
RENAM PROC FAR ;STANDARD LINKAGE TO DOS
PUSH DS ; DO
SUB AX,AX ;
PUSH AX ; NOT
MOV AX,DATA ;
MOV DS,AX ; ALTER!
;--RENAME FILE "A;TEMP.TXT"
MOV DX, OFFSET FCB_ADD ;DS:DX POINTS TO UNOPENED FCB
MOV AH,17H ;REQUEST "RENAME FILE" SERVICE
INT 21H ;INVOKE "RENAME FILE" SERVICE
;-- RETURN TO DOS
RET ;RETurn to DOS
RENAM ENDP ;END of PROCedure
CODE ENDS ;END of CODE Segment
;------------------------------------------------------------------------
END RENAM ;END of routine RENAM
┌──────────────────────────────────┐
│ File Name: ██ list1.asm ██ │
└──────────────────────────────────┘
1 '** SIMPMAZE.BAS
2 '** Generic Maze Generator by Dan Rollins, 04/05/83
3 '** Generates a simple maze. Uses standard Microsoft BASIC.
10 DEFINT A-Z
20 DIM T(5), MZ(100,100) '** maze array (may be expanded to memory size)
30 DIM YD(3),XD(3) :YD(0)=-1 :XD(1)=1 :YD(2)=1 :XD(3)=-1
40 DIM PWR2(3) :PWR2(0)=1 :PWR2(1)=2 :PWR2(2)=4 :PWR2(3)=8
50 RANDOMIZE VAL(RIGHT$(TIME$,2)) '** get a random seed
60 CLS
90 PRINT" SIMPMAZE ... Generic Maze generation program"
95 PRINT" Public domain program written by Dan Rollins 04/05/83
97 PRINT
100 INPUT "horizontal size (26 fits on screen)";H
110 INPUT "vertical size (11 fits on screen) ";V
115 PRINT "calculating maze... please be patient"
120 H=H-1 :V=V-1 '** figure-in 0th elements
130 X=INT(RND*H) :Y=INT(RND*V) '** random starting point
140 GOSUB 1000 '** generate the maze
150 MZ(0,0)=MZ(0,0)+1 '** open a North door for maze entrance
160 GOSUB 2000 '** print the maze
165 INPUT "press enter to generate next maze",A$
170 GOTO 100
996 '** ---- Maze generation subroutine ----
997 '** expects: TR=total rooms, H=horizontal max, V=vertical max
998 '** XD(dir), YD(dir) = motion vectors, PWR2() = powers of 2
999 '**
1000 FOR J=0 TO H :FOR K=0 TO V :MZ(J,K)=0 :NEXT :NEXT '** "close" all doors
1010 RC=0 :TR=(H+1)*(V+1)-1 '** initialize Room Count, Total Rooms
1019 '** ---- Main maze generation loop ---- **
1020 Q=0 :IF RC = TR THEN RETURN '** if Room Count = Total Rooms then done
1030 IF Y>0 THEN IF MZ(X,Y-1)=0 THEN Q=Q+1 :T(Q)=0 '** North
1040 IF X<H THEN IF MZ(X+1,Y)=0 THEN Q=Q+1 :T(Q)=1 '** East
1050 IF Y<V THEN IF MZ(X,Y+1)=0 THEN Q=Q+1 :T(Q)=2 '** South
1060 IF X>0 THEN IF MZ(X-1,Y)=0 THEN Q=Q+1 :T(Q)=3 '** West
1090 IF Q=0 GOTO 1200 '** no move
1098 '** open the doors and move into new room
1099 '**
1100 D=INT(RND*Q)+1 :DIR=T(D) '** choose randomly from list
1110 MZ(X,Y)=MZ(X,Y) + PWR2(DIR) '** add door in current room
1120 Y=Y+YD(DIR) :X=X+XD(DIR) '** move to new room
1130 ND=DIR-2 :IF ND<0 THEN ND=4+ND '** opposite DIR for New Dir
1140 MZ(X,Y)=MZ(X,Y) + PWR2(ND) '** add door in new room
1150 RC=RC+1 '** update Room Count
1160 GOTO 1020
1199 '** Trapped! Scan for an unvisited room.
1200 Y=Y+1 :IF Y>V THEN Y=0 :X=X+1 :IF X>H THEN X=0
1210 IF MZ(X,Y)=0 THEN 1200 '** if empty keep scanning, else....
1220 GOTO 1020 '** see if neighbor has been visited
1996 '** ---- subroutine prints the maze ----
1997 '** only checks for North and West doors
1998 '** change all PRINTs to LPRINTs for hardcopy
2000 CLS
2010 FOR Y=0 TO V
2020 FOR X=0 TO H
2030 IF INT(MZ(X,Y)/2)=MZ(X,Y)/2 THEN PRINT "+--"; :GOTO 2050
2040 PRINT "+ "; '** must have a North door
2050 NEXT X :PRINT "+"
2060 FOR X=0 TO H
2070 IF MZ(X,Y) > 7 THEN PRINT" "; :GOTO 2090 '** must be a West door
2080 PRINT"I ";
2090 NEXT X :PRINT "I"
2100 NEXT Y
2110 FOR X=0 TO H-1 '** add the bottom line
2120 PRINT"+--";
2130 NEXT X :PRINT "+ +" '** maze exit in Southwest corner
2140 RETURN
┌──────────────────────────────────┐
│ File Name: ██ list1.bas ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ║
║ Masthead for PC FIRING LINE/ PC UNDERGROUND ║
║ ║
║ ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Editor │
└──────────────────────────────────┘
Bill Salkin
┌──────────────────────────────────┐
│ Contributing Editors │
└──────────────────────────────────┘
Don Buresh
Gregory Hearn
Ken Holcombe
Guy Kelly
Richard Levaro
George Gordon Noel
Gary M. Rader
William Squire
Ron Watson
┌──────────────────────────────────┐
│ ABComputing │
└──────────────────────────────────┘
ABComputing is the creator and owner of PCFL/PCUG.
Address all correspondence to:
ABComputing
P.O. Box 5503
North Hollywood, CA 91616-5503
ATTENTION: Bill Salkin
Send a S.A.S.E if you wish a reply.
(The company name is pronounced ABC Computing but the
spelling uses one "C".)
┌──────────────────────────────────┐
│ Issue Dates │
└──────────────────────────────────┘
PCFL/PCUG is issued bi-monthly on the following
schedule:
┌────────────────┬─────────────────┐
│ Issue number │ Issue Date │
├────────────────┼─────────────────┤
│ 2 │ May 15 │
│ 3 │ July 15 │
│ 4 │ September 15 │
│ 5 │ November 15 │
│ 6 │ Jan. 15, 1985 │
└────────────────┴─────────────────┘
┌──────────────────────────────────┐
│ Deadlines for Articles │
└──────────────────────────────────┘
Written articles are due on the following schedule:
┌────────────────┬─────────────────┐
│ Issue number │ Date Due │
├────────────────┼─────────────────┤
│ 3 │ June 1 │
│ 4 │ August 1 │
│ 5 │ October 1 │
│ 6 │ December 1 │
└────────────────┴─────────────────┘
┌──────────────────────────────────┐
│ Fee Schedule │
└──────────────────────────────────┘
This fee schedule is subject to change.
┌───────────────────────┐
│ Single Copies │
└───────────────────────┘
Send us $12 and we will supply the diskette(s), mailer,
and postage for PCFL/PCUG. Make checks payable to
ABComputing.
┌───────────────────────┐
│ Subscriptions │
└───────────────────────┘
For those wanting the "ultimate" in convenience, we
offer a one-year (six-issue) subscription for $72, mailed to
your home or business. (The subscription starts with our
current issue.)
Make all checks payable to ABComputing.
┌──────────────────────────────────┐
│ Back Issues │
└──────────────────────────────────┘
Back issues are available from ABComputing at $12 per
issue.
┌──────────────────────────────────┐
│ Distribution │
└──────────────────────────────────┘
Those purchasing PCFL/PCUG are encouraged to make
copies for their friends and associates, as long as
non-profit use is maintained. Recipients of copies are
requested to pay us $6 to help defray the costs of producing
PCFL/PCUG.
┌──────────────────────────────────┐
│ How to Use this Magazine │
└──────────────────────────────────┘
The menu-driven shell you are using is for those
wishing to browse through articles. Standard DOS commands
should be used to print an article. (At the bottom of each
article is the name of the file containing the article.)
┌──────────────────────────────────┐
│ Printers │
└──────────────────────────────────┘
Many printers can not reproduce the full IBM character
set. In particular, some graphic characters used in
PCFL/PCUG will not print properly.
The routine PRETTY1.EXE on Diskette A, causes the
printer to print graphic characters as a series of
asterisks.
To invoke this module, type PRETTY1 after the DOS
prompt:
A>PRETTY1
and press the ENTER key.
Then, the box
┌──────┐
│ Hi! │
└──────┘
will print as:
********
* Hi! *
********
┌──────────────────────────────────┐
│ Trademarks │
└──────────────────────────────────┘
Compaq is a trademark of Compaq Computer Corp.
FREECOPY is a trademark of Squire Buresh Assoc., Inc.
LOTUS 1-2-3 is a trademark of Lotus Development Corp.
MS-DOS is a trademark of Microsoft, Inc.
PC-DOS is a trademark of International Business Machines,Inc.
Tandy 2000 is a registered trademark of Tandy Corp.
UNIX is a trademark of Bell Laboratories.
┌──────────────────────────────────┐
│ File Name: ██ masthead.txt ██ │
└──────────────────────────────────┘
May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ A Comparison of PC Pascal and Pascal/VS ║
║ ║
║ by ║
║ ║
║ J. David Pickens ║
╚═════════════════════════════════════════════════════════════════════════════╝
EDITOR'S NOTE: This is a two-part article. This excerpt is
from the manuscript "A Comparison of PC Pascal and
Pascal/VS" by J. David Pickens, of the Santa Teresa
Laboratory. The second part will appear in the next issue
of PCFL/PCUG.
┌──────────────────────────────────┐
│ Introduction │
└──────────────────────────────────┘
In recent years, Pascal has been used as a general
purpose programming language and as a system program
implementation language. However, "standard" Pascal, as
designed by Niclaus Wirth, lacks many of the features which
are required for general purpose and system programming. As
a result, most implementations of the language have added
extensions to give more capabilities to the Pascal
programmer.
The function of these extensions tend to be similar
from one implementation to the next; unfortunately, the
syntax and underlying philosophy vary considerably among the
various implementations.
Extensions and features of two Pascal implementations
will be examined. One is the IBM Personal Computer Pascal
(PC Pascal for short) and the other is Pascal/VS. (EDITOR'S
NOTE: Pascal/VS is the implementation of Pascal on the IBM
370.)
┌──────────────────────────────────┐
│ Constants │
└──────────────────────────────────┘
┌───────────────────────┐
│ Non-decimal Radicies │
└───────────────────────┘
Pascal/VS permits integer, floating-point, and
character constants to be specified in hexadecimal:
`00FF'X (*Integer*)
`F1'XC (*Character*)
`40100000'XR (*Real*)
In addition, integer constants may also be specified in
binary:
`00001011'B
PC Pascal supports integer constants in hexadecimal,
octal, or binary radix. Floating-point may only be
specified in decimal.
16#FF02 (*Hexadecimal*)
#FF02 (*Hexadecimal*)
8#776 (*Octal*)
2#1010 (*Binary*)
The value of allowing floating point numbers to be
specified in hexadecimal is not obvious. A Pascal/VS
program which uses this facility would not be portable.
Floating-point data is represented differently on the
System/370 than on the IBM Personal Computer.
┌───────────────────────┐
│ Constant Expressions │
└───────────────────────┘
A constant expression (or static expression) is an
expression which can be evaluated at compile time. Both
Pascal Compilers permit constant expressions where constants
are required. Built-in functions such as ABS, ORD, CHR,
etc. may appear in a constant expression.
const
PI = 3.14159;
TWO_PI = 2 * PI;
ORDA = ORD(`A');
ORDA1 = ORDA + 1;
type
MINUTES = 0..24*60;
SECONDS = 0..sqr(60)*24;
┌───────────────────────┐
│ Structured Constants │
└───────────────────────┘
A structured constant is a constant which is of a
structured data type. Both compilers support structured
constant and with almost identical syntax.
const
LETTERS = [`A'..`Z',`a'..`z'];
type
COMPLEX = record
RE,IM: REAL
end;
const
Q = COMPLEX(3.0,4.0);
type
VEC = array[-2..2] of INTEGER;
const
VECT = TVEC(5,4,3,2,1);
┌──────────────────────────────────┐
│ Data Types │
└──────────────────────────────────┘
┌───────────────────────┐
│ Integers │
└───────────────────────┘
Integer variables in Pascal/VS can occupy 1,2,3, or 4
bytes. Pascal/VS supports unsigned integers which may
occupy 1,2, or 3 bytes. The default integer size is 4 bytes
(1 full word). To declare an integer with a smaller size, a
subrange type definition is prefixed with the word packed.
type
HALFWORD = packed -32768..32767; (*2 bytes, signed*)
UNSIGNED = packed 0..65535; (*2 bytes, unsigned*)
BYTE = packed 0..255; (*1 byte, unsigned*)
Pascal/VS does not support unsigned, full word
integers.
PC Pascal supports 1 and 2 byte integers; both signed
and unsigned. To declare an unsigned integer, the
predefined type WORD is used. Subrange types are
automatically mapped to single bytes if the range permits
it.
var
SIGNED_BYTE : -127..127; (*1 byte variable, signed*)
UWORD : WORD; (*2 bytes variable, unsigned*)
type
BYTE = WRD(0)..255 (*1 bytes, unsigned*)
Most Pascal compilers which allow byte packing of
integer subranges do it implicitly, as is done in PC Pascal.
On the other hand, Pascal/VS will map an integer subrange to
a 4 byte word unless it is qualified with the word "packed".
Unfortunately, most Pascals would diagnose a "packed"
subrange as an error. (Standard Pascal allows only
structured types to be "packed"). In other words, Pascal/VS
has extended the language to support a feature which could
have been supported within the language.
PC Pascal does not support integers which are greater
than two bytes in length (the word length of the IBM-PC).
As a consequence, many Pascal programs which depend on
integers outside the range of -32767 to 32768 would need
major redesigning in order to run under PC Pascal. (One
possibility is to add a predefined type called "DOUBLE" or
"LONG_INTEGER," which would allow 4 byte integers to be
declared.)
┌───────────────────────┐
│ Floating Point │
└───────────────────────┘
Pascal/VS supports two precisions of floating point
data: double precision (8 bytes) and single precision (4
bytes). The standard predefined type REAL is used to
declare a double precision variable; a predefined type
called "SHORTREAL" was added to declare a single-precision
variable.
var
R: REAL; (*double precision floating point*)
S: SHORTREAL; (*single precisions*)
PC Pascal supports only one floating point type which
consists of 4 bytes: a 24 bit mantissa and an 8-bit binary
exponent, giving about 7 digits of precision.
┌──────────────────────────────────┐
│ Conformant/ Dynamic Arrays │
└──────────────────────────────────┘
A well known problem in standard Pascal is in the
compatibility rules governing array variables. Arrays of
different lengths are never compatible and, as a result, one
is unable to write a general procedure for manipulating
vectors and matrices.
PC Pascal has defined a type mechanism called "SUPER
ARRAYS" which permits you to define a class of arrays with
different lengths. For example:
type
VECTOR = super array [1..*] of REAL;
MATRIX = super array [1..*,1..*] of REAL;
VECT10 = VECTOR(10); MATDEC = MATRIX(100,100);
var
ROW: VECT10; COL: VECTOR(10);
MAT: MATRIX(40,40);
procedure INVERT(var M: MATRIX); EXTERN;
begin
...
INVERT(MAT); (*allows any MATRIX type*)
...
end;
In a variable declaration, the super type must be
qualified with operands which designate the array length (as
in the declaration of COL and MAT above.)
If a formal reference parameter is being declared, only
the super type name need appear (as in the declaration of
INVERT above). Any variable declared with the corresponding
super type may be passed as the formal parameter, regardless
of the length.
As a by-product of the super type mechanism, PC Pascal
has added dynamic arrays - arrays for which a length is not
determined until execution time. Dynamic arrays are defined
by declaring a pointer to a super array. The length of the
pointer's object is determined when the object is allocated
(via NEW).
type
VECTOR = super array [1..*] of INTEGER;
var
ROWP : @VECTOR;
L : INTEGER;
procedure INVERT(var M: MATRIX); EXTERN;
begin
...
NEW(ROWP,L); (*Allocates a VECTOR array of length L*)
...
end;
┌──────────────────────────────────┐
│ Strings │
└──────────────────────────────────┘
Both compilers support character-string variables which
may vary in length at execution time.
Pascal/VS has added a predefined type called "STRING".
When used in a variable declaration, the word STRING must be
qualified with a positive integer constant which specifies
the maximum length of the string variable.
var S: STRING(100); (*S declared as string with max of 100*)
PC Pascal has added two predefined types to define
strings: "STRING" and "LSTRING". STRING defines a super
array which is equivalent to:
packed array[1..*] of CHAR
LSTRING defines a string with a length which may vary
at execution time. Thus, the type LSTRING in PC Pascal is
similar to the type STRING in Pascal/VS.
Both STRING and LSTRING are qualified with a length
when used in a variable declaration.
Both compilers have relaxed the strict type
compatibility rules in handling string data. A string
variable may be assigned to another and their lengths need
not be the same.
PC Pascal does not allow a formal reference parameter
of type STRING or LSTRING to be assigned to, or compared
with, another string variable. Pascal/VS has no such
restriction.
Pascal/VS allows varying-length string variables to be
up to 32767 characters in length; in PC Pascal, the limit is
255 characters. (EDITOR'S NOTE: At this point the reader is
directed to the following footnote:
...The first release of Pascal/VS had a
255 character limit on string, but many
customers complained that the limit was
too small for many of their applications.
As a result, the second release moved the
limit up to 32767...)
┌──────────────────────────────────┐
│ Sets │
└──────────────────────────────────┘
Both compilers have similar restrictions on the use of
set variables. "Set of CHAR" is supported by each compiler.
Sets with negative members are not allowed. The ordinal
value of the largest member of a set is 255.
The two compilers map set variables differently. In
Pascal/VS a variable declared as
set of `A'..`Z'
will occupy 32 bytes (256 bits). Such a variable in PC
Pascal would occupy the least number of words needed to
contain the largest member "Z" (in ASCII), which would be 12
bytes (96 bits).
In short, Pascal/VS allocates as many bytes as
necessary to hold all members of the fundamental base type,
that is, the type from which the base subrange was derived
(In the example above, the fundamental base type is CHAR.)
Pascal/VS maps packed sets more compactly. For
example, a variable declared as
packed setof 0..7
will occupy 1 byte (8 bits).
Pascal/VS supports sets that are one byte in length (as
shown in the last example.) In contrast, PC Pascal requires
all sets to occupy an even number of bytes, thus the
smallest set size is 2 bytes.
┌──────────────────────────────────┐
│ Variable Attributes │
└──────────────────────────────────┘
Both compilers support static-internal and
static-external variables.
Pascal/VS has added three new reserved words to the
language: static, def, and ref. These words are used in the
similar context as var to declare variables.
"Static" specifies that the following variable
declarations are static-internal. "Def" specifies that the
variables are to become names of COMMON sections. "Ref"
specifies that the variables are external references.
static (*internal*)
varid1 : typedef1;
varid2 : typedef2;
...
def (*Named common*)
varid1 : typedef1;
varid2 : typedef2;
...
ref (*External static*)
varid1 : typedef1;
varid2 : typedef2;
...
In PC Pascal, variable declarations may be qualified
with an attribute description enclosed in square brackets.
This descriptor designates the storage class of the
variable.
var[PUBLIC] (*publicly assessable variable*)
varid1 : typedef;
var[EXTERN] (*external reference*)
varid1 : typedef;
var[STATIC] (*static internal*)
varid1 : typedef;
Pascal/VS provides a way to share non-static variables
across compilational units in order to provide reentrancy.
Variables declared with the var construct in the outermost
level of the module will be mapped directly on top of the
variables which are declared local to the main program. In
effect, the variables which were allocated for the main
program are accessible from all modules. In the following
example, the variables A and R will be shared across the two
modules at execution time (assuming the two are link-edited
together).
(*main program*) (auxiliary module*)
program ABC; segment XYZ;
var A: Integer; var A: Integer;
R: Real; R: Real;
begin
...
end.
This approach has the problem of being very insecure.
If the variables declared in the outer level of a module do
not match in type, number, and order to those in the main
program, the results will be unpredictable.
┌──────────────────────────────────┐
│ File Name: ██ pas1.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ Diskette B Program Description ║
║ ║
║ by ║
║ ║
║ Bill Salkin ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┐
│ Introduction │
└──────────────────────────────────┘
This column describes the programs, both complete and
DEMOnstration, on Diskette B.
┌──────────────────────────────────┐
│ Program Description │
└──────────────────────────────────┘
Unless otherwise noted, all programs run under any
release of DOS on a 128K IBM-PC, with either monitor.
┌─────────────────────┐
│ Complete Program │
├─────────────────────┴─────────────────────────────────┐
│ 83 Standard PC-FORTH by Guy Kelly │
│ See "The FORTH Processor" in FORTH column for details │
│ Use batch file: FORTH.BAT │
└───────────────────────────────────────────────────────┘
┌─────────────────────┐
│ Complete Program │
├─────────────────────┴─────────────────────────────────┐
│ Programmer's Calculator by R. Moak │
│ Invoke: B>PC, or B>GC │
└───────────────────────────────────────────────────────┘
┌─────────────────────┐
│ Complete Program │
├─────────────────────┴─────────────────────────────────┐
│ Polymaze by RollinSoft │
│ A maze-generation program │
│ Monitor: Color only │
│ Invoke: B>POLYMAZE │
└───────────────────────────────────────────────────────┘
┌─────────────────────┐
│ Complete Programs │
├─────────────────────┴─────────────────────────────────┐
│ All programs supplied by Computer Innovations, Inc. │
│ │
│ SQ.C - squeezes a file to save diskette space │
│ SQ.EXE - the executable module │
│ Invoke: B>SQ filespec │
│ │
│ GRABBAG.C - on Diskette A, originally called USQ.C │
│ because it unsqueezes modules squeezed by SQ.EXE. │
│ GRABBAG.EXE - the executable module │
│ Invoke: B>GRABBAG filespec │
└───────────────────────────────────────────────────────┘
┌─────────────────────┐
│ DEMOs │
├─────────────────────┴─────────────────────────────────┐
│ Trace86 by Morgan Computing Company. Inc. │
│ Invoke: B>T86 │
└───────────────────────────────────────────────────────┘
┌──────────────────────────────────┐
│ File Name: ██ pcugintr.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ║
║ Sponsors ║
║ ║
║ ║
╚═════════════════════════════════════════════════════════════════════════════╝
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▌ 2034 Blake Street, Berkeley, CA 94704
▌ Blaise Computing, Inc. (415)540-5441
▌ Software developers for programmers and
▌ system programmers for both Pascal and C.
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▌ Businessland, Inc. 14144 Ventura Blvd, Sherman Oaks, CA 91403
▌ (818)788-1170
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▌ Computer Innovations,Inc. 980 Shrewsbury Avenue, Suite J-509
▌ Tinton Falls, NJ 07724
▌ (800)922-0169
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▌ Guy Kelly 2507 Caminito La Paz, La Jolla, CA 92037
▌ (619)454-1307
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▌ 1033 N. Sycamore Avenue, Hollywood, CA 90038
▌ OPAMP TECHNICAL BOOKS (213)464-4322
▌ Computer books for all interests
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▌ Ron Watson (213)884-9967
▌ Data Processing
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▌ P.O. Box 51454-5454, San Jose, CA 95151
▌ SCIOPT Enterprises (408)281-0869
▌ Engineering and scientific applications for
▌ the IBM PC and custom 8087 programming.
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▌ 1155 Meridian Avenue, Suite 218
▌ TELECON SYSTEMS San Jose, CA 95125
▌ (408)275-1659
█████████████████████████████████████████████████████████████████████
┌──────────────────────────────────┐
│ File Name: ██ sponsors.txt ██ │
└──────────────────────────────────┘
Copyright 1984 by ABComputing May 15, 1984
╔═════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ║
║ Table of Contents ║
║ ║
║ ║
╚═════════════════════════════════════════════════════════════════════════════╝
┌─────────────────────────────────────┐
│ Diskette A │
└─────────────────────────────────────┘
┌─────────────────────┐
│ Main Menu │
├─────────────────────┴───────────────────┐
│ Editor's Console Set RGB Colors │
│ Operating Systems Hardware │
│ Languages PC Underground │
└─────────────────────────────────────────┘
┌─────────────────────┐
│ Editor's Console │
├─────────────────────┴───────────────────┐
│ Table of Contents Copyright Notice │
│ Masthead Editorial │
│ Enhancements Sponsors │
│ Writer's Guide KEDIT Review │
│ Grab Bag! │
└─────────────────────────────────────────┘
┌─────────────────────┐
│ Set RGB Colors │
├─────────────────────┴───────────────────┐
│ Change foreground color │
│ Change background color │
│ Change prompt line color │
│ Change border color │
└─────────────────────────────────────────┘
┌─────────────────────┐
│ Operating Systems │
├─────────────────────┴──────────────────────────────────────────┐
│ "DOS - Past, Present, and Future" by Don Buresh │
│ "Is It IBM-PC Compatible?" by Don Buresh │
└────────────────────────────────────────────────────────────────┘
┌─────────────────────┐
│ Hardware │
├─────────────────────┴──────────────────────────────────────────┐
│ "Readiscope - it Really Works" by Ken Holcombe │
└────────────────────────────────────────────────────────────────┘
┌─────────────────────┐
│ Languages │
├─────────────────────┴───────────────────┐
│ Ada Assembly Language │
│ BASIC C │
│ FORTH FORTRAN │
│ LISP Pascal │
└─────────────────────────────────────────┘
┌─────────────────────┐
│ Ada │
├─────────────────────┴──────────────────────────────────────────┐
│ "The Ada Tutorial - Part I" by George Gordon Noel │
│ "Review of Six Ada Books" by George Gordon Noel │
│ "Ada Programs" by George Gordon Noel │
└────────────────────────────────────────────────────────────────┘
┌─────────────────────┐
│ Assembly │
├─────────────────────┴──────────────────────────────────────────┐
│ "Introduction to Assembly Language" by Bill Salkin │
│ "Assembly Programs" by Bill Salkin │
│ "DOS 1.1, 2.0 Sequential File-Reading" by Bill Salkin │
└────────────────────────────────────────────────────────────────┘
┌─────────────────────┐
│ BASIC │
├─────────────────────┴──────────────────────────────────────────┐
│ "Simpmaze Documentation" by Bill Salkin │
│ "Simpmaze Source Code" by Dan Rollins │
└────────────────────────────────────────────────────────────────┘
┌─────────────────────┐
│ C │
├─────────────────────┴──────────────────────────────────────────┐
│ "Introduction to C" by Ron Watson │
│ "C Programs" by Ron Watson │
└────────────────────────────────────────────────────────────────┘
┌─────────────────────┐
│ FORTH │
├─────────────────────┴──────────────────────────────────────────┐
│ "Venture FORTH" by Guy Kelly │
│ "FORTH Reference Documents" by Guy Kelly │
│ "The FORTH Processor" by Guy Kelly │
└────────────────────────────────────────────────────────────────┘
┌─────────────────────┐
│ FORTRAN │
├─────────────────────┴──────────────────────────────────────────┐
│ "Roots of 3rd and 4th Order polynomials" by William Squire │
│ "FORTRAN Source Code" by William Squire │
└────────────────────────────────────────────────────────────────┘
┌─────────────────────┐
│ LISP │
├─────────────────────┴──────────────────────────────────────────┐
│ "Converting Infix to Prefix Notation" by Gary M. Rader │
│ "Source Code for ITOP" by Gary M. Rader │
└────────────────────────────────────────────────────────────────┘
┌─────────────────────┐
│ Pascal │
├─────────────────────┴──────────────────────────────────────────┐
│ "A Comparison of PC Pascal and Pascal/VS" by J. Pickens │
└────────────────────────────────────────────────────────────────┘
┌─────────────────────┐
│ PC Underground │
├─────────────────────┴──────────────────────────────────────────┐
│ "Diskette B Program Description" by Bill Salkin │
└────────────────────────────────────────────────────────────────┘
┌─────────────────────┐
│ Splita.bat │
├─────────────────────┴──────────────────────────────────────────┐
│ Splits Diskette A into single-sided diskettes. │
└────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Diskette B │
└─────────────────────────────────────┘
A fuller description of each program is provided in the PC
Underground section of PCFL/PCUG.
┌─────────────────────┐
│ Complete Program │
├─────────────────────┴─────────────────────────────────┐
│ 83 Standard PC-FORTH by Guy Kelly │
└───────────────────────────────────────────────────────┘
┌─────────────────────┐
│ Complete Program │
├─────────────────────┴─────────────────────────────────┐
│ Programmer's Calculator by R. Moak │
└───────────────────────────────────────────────────────┘
┌─────────────────────┐
│ Complete Program │
├─────────────────────┴─────────────────────────────────┐
│ Polymaze by RollinSoft │
└───────────────────────────────────────────────────────┘
┌─────────────────────┐
│ Complete Programs │
├─────────────────────┴─────────────────────────────────┐
│ SQ.C by Computer Innovations, Inc. │
│ SQ.EXE " " " " │
│ GRABBAG.EXE (GRABBAG.C ON DISKETTE A) " " " " │
└───────────────────────────────────────────────────────┘
┌─────────────────────┐
│ DEMO │
├─────────────────────┴─────────────────────────────────┐
│ Trace86 by Morgan Computing Co., Inc. │
└───────────────────────────────────────────────────────┘
┌─────────────────────┐
│ Splitb.bat │
├─────────────────────┴─────────────────────────────────┐
│ Splits Diskette B into single-sided diskettes. │
└───────────────────────────────────────────────────────┘
┌──────────────────────────────────┐
│ File Name: ██ toc.txt ██ │
└──────────────────────────────────┘
Volume in drive A has no label
Directory of A:\
ADA1 TXT 16278 5-15-84 12:33a
ADABOOK REV 12973 5-15-84 12:17a
ASM1 TXT 21162 5-15-84 12:14a
ASM2 TXT 19749 5-15-84 12:06a
BASIC1 TXT 9178 5-15-84 12:18a
C1 TXT 15815 5-15-84 12:41a
CHANGES TXT 5494 5-15-84 12:58a
CPYRIGHT TXT 1306 5-15-84 12:57a
DOS1 TXT 13882 5-15-84 12:18a
DOS2 TXT 6440 5-15-84 12:19a
EDITOR TXT 4183 5-15-84 12:19a
FILES160 TXT 1489 1-26-89 4:19p
FORT1 TXT 7980 5-15-84 12:19a
FORTH1 TXT 15235 5-15-84 12:43a
FORTH2 TXT 16422 5-15-84 12:45a
FORTH3 TXT 3366 5-15-84 12:17a
GO BAT 38 10-19-87 3:56p
GO TXT 694 12-01-88 4:26p
GRABBAG C 10321 5-15-84 12:27a
ITOP LSP 3740 5-15-84 12:52a
KEDIT TXT 22062 5-15-84 12:01a
LISP1 TXT 9141 5-15-84 12:52a
LIST1 ADA 2295 5-15-84 12:57a
LIST1 ASM 16092 5-15-84 12:57a
LIST1 BAS 3351 5-15-84 12:41a
LIST1 C 881 5-15-84 12:42a
LIST1 FOR 5561 5-15-84 12:20a
MASTHEAD TXT 5240 5-15-84 12:08a
PAS1 TXT 14621 5-15-84 12:55a
PCFL EXE 8576 5-15-84 12:12a
PCUGINTR TXT 2863 5-15-84 12:56a
PRETTY1 COM 223 1-01-80 3:07a
READISCO PE 13126 5-15-84 12:20a
SPLITA BAT 1165 5-15-84 12:56a
SPONSORS TXT 2220 5-15-84 12:59a
TOC TXT 7581 5-15-84 12:06a
WRITERS GDE 2518 5-15-84 12:59a
37 file(s) 303261 bytes
38912 bytes free