BANCStar
BANCStar is a language that was used in production in finance in the 1990s, even though it looks like an esoteric language. BANCStar was not originally intended to be written by humans, but only by a compiler, the so-called screen generator. The syntax of BANCStar is very bare because of that. However, programmers found the power of the screen generator lacking, so they started to modify BANCStar programs by hand.
Language capabilities
There is no real documentation, so a lot of the information we know is based on archaeological research and experimentation.
Syntax
A BANCStar program is a sequence of lines. Each line consist of a list of four comma-separated fields, each of which can contain an integer or be blank. The comma field delimiters are required even when some fields are left blank.
The first number in the list is the opcode, which describes the operation being performed by this line. See the table below for the list of opcodes discovered so far.
The numbers can be positive or negative, and are probably limited to between -32768 and 32767.
Instructions
Known values for opcodes are detailed below.
Opcode | Operands | Description | ||
---|---|---|---|---|
1–2000 | p1 | r | p2 | Display prompt at position (x, y), where p1 = 100*y+x. A response field is allocated at position p2, and is r characters wide. A position of zero means to not display that component. The response field is prepopulated with the prompt cell's current value. |
2999 | Introduce new page (body of code similar to a source file). AKA "stop code". | |||
3000 | x | op | y | Conditional: if x op y, execute next line |
3001 | x | op | y | Block conditional: if not x op y, skip until next end-of-block |
3001 | End-of-block | |||
3101 | x | op | y | Reverse block conditional: if not x op y, skip backwards until next reverse end-of-block |
3101 | Reverse end-of-block | |||
7000–7999 | ? | ? | ? | "Draw commands". Draws some sort of "picture" specified in the first parameter. |
Opcode | Operands | Description | ||
8000 | clr | p1 | p2 | Window: sets up some sort of window using positions p1 and p2 (possibly corner points). clr = bg*16+fg, where fg and bg are ANSI (possibly actually PC) colour codes. The high 8 colours are considered to be blinking. |
8100 | n | y | x | Print text file with name "n.TXT" at (x, y). |
8400 | "Save address", used to save the return address for subroutine calls (possibly stores the address of the instruction after the next instruction into variables 1908 and 1909?) | |||
8500 | n | Goto page n. n must be less than or equal to 500. | ||
8500 | 500+f | Goto function key f, in the range [1, 20] | ||
8500 | 1000+p | Goto prompt p, in the range [1, 2000] | ||
8500 | 4000+t | Goto "a particular transaction within a document module", specified by t in the range [1, 24] | ||
8500 | 4000+asc | Goto a miscellaneous thingy; asc is an ASCII code. P: "Product & Sales"; M: "Back to Menu"; E: "Exit BANCStar"; S: "Storage"; T: "Multi-task menu". | ||
8550 | ? | ? | ? | "Combination goto"; complicated business |
8550 | 11908 | 11909 | According to the LINK source, "Our particular way of returning from a Branch & Link operation.". Seems to use prompts 1908/1909 in some fashion, beyond that is unknown | |
8560 | p | Execute DOS command specified by prompt p. Presumably taken from the prompt's name. | ||
8600 | Activate F6 & F7 | |||
8601–8607 | Deactivate F6 & F7 | |||
8608 | Deactivate F2, activate all other F-keys | |||
8609 | Deactivate F2, activate all other F-keys | |||
8610+f | Deactivate F-key f (from F0 to F10), activate all other F-keys | |||
8621–8630 | Deactivate all F-keys | |||
8650 | m | Set video mode m (unknown meaning, possibly a VESA number) | ||
8700 | "Auto-solve" | |||
9001 | "Auto-save" | |||
9100 | "Host interface (native)" | |||
9200, 9201 | e | p | q | Data model command "run procedure"; prompts p and q (both optional). e seems to denote some sort of subfield: 0: "number"; 1: "label"; 2: "value". |
9300, 9301 | e | p | q | Data model command "put to data model"; arguments as above |
9400, 9401 | e | p | q | Data model command "get from data model"; arguments as above. NB: some live examples of 9401 have the prompt addresses added to 10000, but it's unclear why. Other samples are normal. |
Opcode | Operands | Description | ||
10000–11999 | x | y | z | Arithmetic instruction (see below) |
16000+m | d | x | y | File read/write. m is a value that specifies the exact operation (see below). d = dr+10*pos, where dr is the drive number (0=>A, 1=>B, etc), and pos is the position (-1: current). x and y can be prompt numbers in [1, 2000], or an "indirect prompt" of the form 10000+p, or a "table entry (description)" of the form 20000+p, or a "table entry (item)" of the form 30000+p (where p is a prompt number). |
20000+p | "Form display command (long prompt name)" | |||
30000+p | x | y | q | Table commands. Some prompt p is specified in the command head. q = 10*z+op, where op is as specified below. p, x, y, and z are parameters of the resulting table operator. |
Arithmetic instructions
The most complicated type of instruction seems to be arithmetic instructions. Here, the first number is 10000+d, where d is the address of one of the 2000 variable cells ("prompts") as the destination operand.
The other three numbers are of the form (10v+p) or (22000+10n+p) where p is an operation code, v is a variable cell in the range [1, 2000], and n is a constant literal integer.
When a parameter is unneeded, it is usually set to 22002 (i.e. "add 0").
The arithmetic instructions which can be constructed are as in the following table. Here dest is the destination cell from the first number and p1/p2/p3 are the operation codes extracted from the other three numbers. Where an operand's value is always being treated as an address it is marked v1; when it's always a literal number it's written n1; and if it can be either then it is written a1.
If an operand must be left unused (22002), then its operation code is blank.
In some cases, a spare operand can optionally be used to squeeze an extra operation onto the same line: we call these "arithterms". Such operands are marked with "A" in the table below. If you don't want to use the arithterm, set that number to 22002, which is equivalent to the arithterm "add 0". An example of how arithterms work follows this table.
p1 | p2 | p3 | Instruction | Description | Notes |
---|---|---|---|---|---|
2 | A | A | Set | Set dest equal to a1. | |
1 | A | A | Negate | Set dest equal to negative-a1. | |
0 | A | A | Length | Set dest to the length of a1. | Unknown what the length of a literal integer is. |
5 | Clear | Clear dest. Samples seen all have the same address in v1 and dest (not known if this is required). | It's unknown how this relates to setting the cell to zero; might depend on data type. | ||
7 | A | A | Logarithm | Calculate the logarithm of a1 and store it in dest. | Logarithm base is unknown, probably either e or 10. |
8 | A | A | Truncate | Calculates the positive integer part of a1 and stores it in dest. | Unknown how this interacts with other datatypes |
Exponentiation operations | |||||
6 | 2 | A | Power | Set dest to a1 raised to the power of a2. | |
6 | 3 | A | Power | Believed to be the same as the above. | Speculative |
6 | 1 | A | Inverse power | Set dest to a1 raised to the power of negative-a2. | Speculative |
6 | 4 | A | Root | Set dest to the a2-th root of a1. | Speculative |
Miscellaneous operations | |||||
6 | 5 | 2 | Substring | Set dest to the substring of v1 that starts at a2 and has length a3. | Not known if strings index from 0 or from 1 |
6 | 6 | A | Time | Get the system time and store it in dest. v1 always seems to be the same address as dest (not known if this is required). n2 always seems to be 0. | Format of time value is unknown |
Date operations | |||||
9 | 1 | Future date 365 | Performs some operation on a1 and a2, storing the result in dest. | Date routines are very poorly understood. | |
9 | 2 | Future date 360 | Performs some operation on a1 and a2, storing the result in dest. | Date routines are very poorly understood. | |
9 | 3 | Date difference | Calculates the number of days between dates a1 and a2, storing the result in dest. | Date routines are very poorly understood. | |
9 | 4 | ? | Mystery date operation | Function unknown, described in LIST source as "Future Date 360 and number of days". It is noted there that nobody has been able to use this. | Date routines are very poorly understood, this one most of all. |
In all cases, we don't know how error conditions (divide by zero, substring out of range, etc) are treated.
In LIST, these are decoded by L_COMMTS.C lines 869–1691.
Arithterm example
An arithterm is used to squeeze an extra operation onto the same line as an existing one. Each arithterm takes up a single BANCStar number and encodes one of the four arithmetic operators (+-×÷) plus a constant or variable cell.
Arithterms are encoded in the way mentioned above (i.e. as 10v+p or 22000+10n+p). The operation code p can be one of the following:
p | 1 | 2 | 3 | 4 |
operator | - | + | × | ÷ |
The arithterm takes effect after the main operation. For example, this BANCStar line calculates the logarithm of the literal number 42, and saves it into variable cell 222:
10222,22427,22002,22002
Note the two optional arithterms have been left as 22002. Now we will change one of them to "subtract 64", which encodes as 22641.
10222,22427,22641,22002
Executing this single line now calculates the logarithm of 42, subtracts 64, and stores the result in cell 222. We can add one more arithterm:
10222,22427,22641,7773
Now this single line calculates log(42), subtracts 64, multiples by the value of variable cell 777, and finally stores the result in cell 222.
Conditional instructions
The various conditional instructions (conditional, block conditional, reverse block conditional) use a different encoding for operands.
The first operand (x) must always be a variable cell ("prompt"). It is given simply as the prompt number, in the range [1, 2000].
The second operand may be one of the following:
Form | Meaning |
---|---|
10000 + z | Nonnegative value z, in range [0, 9999] |
20000 + p | Value of prompt p, in range [1, 2000] |
30000 + c | ASCII character c, in range [0, 255] |
The operation argument op in the conditional instructions are encoded differently depending on the remaining operands.
Page conditionals
The op argument may have 10 added to it (i.e. {12, 13, 14, 15, 16}), in which case it signifies a "page conditional". The meaning of this is unclear, but it looks like any conditional statement may be used as a "page conditional".
Unary operations
Two unary operations are available by omitting the last operand (y) or setting it to zero. The following operand table is used in this case:
Op | 1 | 2 |
Relation | null | not null |
General comparisons
The table below is used if both operands are numbers, or if x is an "alpha" (string?) variable and y is an ASCII character:
Op | 1 | 2 | 3 | 4 | 5 | 6 |
Relation | < | ≤ | = | ≥ | > | ≠ |
Special
If the first operand is a prompt of type 7 (alpha, believed to be a string), and the second operand is not an ASCII character, the following table is used:
Op | 1 | 2 | 3 | 4 | 5 | 6 |
Relation | null | not null | = | ≠ | until null | while null |
The last two operators seem to provide some sort of looping capability.
File instructions
Add 16000 to get the instruction number (see above). Note there seems to be some duplication of functionality here, I don't know if there is any hidden meaning.
Operation | Meaning |
---|---|
160 | Continue reading (comma or CR/LF) |
161 | Open file for fixed-length read |
162 | Open file for comma or CR/LF read |
163 | Open file for CR/LF read |
164 | Open file for fixed-length read, then close |
165 | Open file for comma or CR/LF read, then close |
166 | Open file for CR/LF read, then close |
167 | Continue reading fixed length |
168 | (n/a) |
169 | Close file |
170 | Continue writing (comma or CR/LF), |
171 | Open existing file for fixed-length write |
172 | Open existing file for comma or CR/LF write |
173 | Open existing file for CR/LF write |
174 | Open existing file for fixed-length write, then close |
175 | Open existing file for comma or CR/LF write, then close |
176 | Open existing file for CR/LF write, then close |
177 | Continue reading fixed length |
178 | (n/a) |
179 | Close file |
180 | Continue writing (comma or CR/LF) |
181 | Open new file for fixed-length write |
182 | Open new file for comma or CR/LF write |
183 | Open new file for CR/LF write |
184 | Open new file for fixed-length write, then close |
185 | Open new file for comma or CR/LF write, then close |
186 | Open new file for CR/LF write, then close |
187 | Continue reading fixed length |
188 | (n/a) |
189 | Close file |
Table instructions
See the entry for 30000+p in the main instruction table.
Each table operator has parameters p, x, y, and z as specified earlier. p is always a prompt. x may be a prompt number, or 10000+n, denoting some number n in [0, 9999]. y and z are both simple numbers unless otherwise specified.
Operator | Name | Description in LIST source | Notes |
---|---|---|---|
1 | table search | p <-- x at y (z) [return location] | |
2 | table search | p <-- x at y (z) [return description] | |
3 | table search range | p <-- x at y (z) [return location] | |
4 | table search range | p <-- x at y (z) [return description] | |
5 | table search range pairs | p <-- x at y (z) [return location] | |
6 | table search range pairs | p <-- x at y (z) [return description] | (the LIST source actually says "return location", assumed typo) |
7 | table transfer | p <-- y (z item) [return item] | |
8 | table transfer | p <-- y (z item) [return description] | |
9 | table transfer | p --> y (z item) [return item] | note direction of arrow is reversed |
10 | table transfer | p --> y (z item) [return description] | as above |
Prompt file
The "prompts" (variable cells) used by a BANCStar program seem to have some metadata stored in a prompt file (*.PFL). It is probable that the prompt number is just the line number in this file. Each line has three comma-separated values: name (a human-readable string), type (an integer of unknown meaning), and length (an integer unknown meaning).
Some sample prompt entries:
Pmts/Year,2304,2 Term(# Pmts),204,3 Principal,205,10 BALANCE,205,10 Payment,205,8 Balloon,205,7 Intrest Rate,206,7 Total P&I,205,12 Date,2303,12 #1 Pmt Date,2303,12 Trans Date,3,12
Prompt type
The LIST source code specifies the following prompt types:
Type | Meaning |
---|---|
0 | no data? |
1 | Telephone number |
2 | U.S. social security number |
3 | Date |
4 | Number |
5 | Currency (USD) amount |
6 | Rate (a percentage?) |
7 | Alpha (an ASCII value?) |
8 | Constant |
Prompts of type 8 are used solely as on-screen display text, e.g.:
Press the ENTER key to continue . . .,8,
However, the sample data with the program include prompts with other type codes, e.g. 2304. The last digit always seems to match up with the above table. It's not known what the rest of the type code means.
Prompt length
The length value seems to be related to the size of the text entry box displayed alongside the prompt. Possibly the size specified in the prompt-display command must be less than or equal to this length?
Special variables
There seems to be some "special variables" (details are not quite known for certain):
- 1547 = Pause flag
- 1908 = Half of the return address
- 1909 = Half of the return address
Implementation
The implementation is not available yet. We heard someone was trying to rescue the original implementation from an old floppy disk, but he then went missing. We are sure there's nothing fishy about this.