Friday, September 23, 2022

A Short Description of VTL-2 Expressions (Very Tiny Language pt 1)

(Because some people want to know:)

The simplest way to describe VTL (Very Tiny Language) is to say it it is very small, and it turns your 8-bit microcomputer into a programmable integer calculator. Typical assembler implementations can fit into well less than 1 kilobyte of ROM.

Comparing this to the programming language BASIC, which can also be described as a way to turn your computer into a programmable desktop calculator. a typical small BASIC interpreter capable of handling floating point (fractional/scientific notation) numbers takes about 8 to 24 kilobytes of object code on a typical 8-bit microcomputer. BASIC on the original IBM PC took about 32 kilobytes. Bywater BASIC (something close to the original BASIC on the IBM 5150 PC) on a modern 64-bit computer takes about 180 kilobytes. 

The Unix utility bc is another language that turns your computer into a calculator with arbitrary precision, and it has a typical object code image of about 90 kilobytes on a 64-bit computer.

Obviously, you won't get the functionality of a full BASIC or bc (or Forth) with VTL. But you can write small programs with it, so it's interesting.

Anyway, the available manuals all tend to be PDFs, and you may not want to go to the trouble of finding one and downloading it and hoping it's relevant to the implementation you have, so I'm writing down my impressions of VTL-2, with some examples. 

This post focuses on expressions in VTL-2. 

One word of warning, VTL hardly gives any feedback at all. In fact, my conversions to the MC-10 and the Color Computer don't even give  you a cursor. (I should try to fix that, I suppose, but not today.)

But it does at least give you the 

OK 

prompt when it's ready for more commands.

No error messages. (Which I do not intend to try to fix.)

If you want see whether the VTL interpreter you've just gone to the trouble of downloading, assembling, and loading into your target machine is running, try this:

?=1+1

Don't forget the = after the ? . This is not a dialect of BASIC. 

It should print out 2 for you. That means the expression grammar part is working at some level.

So, let's proceed with syntax and semantics, etc. --

Assignment:

Assignment is done with the usual = symbol:

A=A+1

and such. 

Variables:

All variables are pre-declared and pre-allocated. Since the variable names are limited to one letter or character, there aren't that many, and it takes less memory to have them already exist than to write code to let you declare and allocate them.

The 26 variables A through Z are integer variables you can use as you want. 

Output:

Printing re-uses the assignment syntax:

?=A

prints whatever integer value is in A to your output device.

Note that it sort of looks like the short-cut available in many BASICs, but is not.

? A

does something hard to explain just yet, but does not really do what you want, even though it may look like it does.

Printing strings is a logical extension to the print syntax:

?="APPLES"

puts the string 

APPLES

on your output device. 

You want to know why the = is in there? Re-using the syntax allows re-using the code and keeping it small, is the best explanation I can think of. (I assume. I am neither Gary Shannon nor Frank McCoy. Ask them if you get a chance.)

More variables, including system variables:

Variables other than A through Z? 

All variable names are one character. 

Take a look at your nearest ASCII chart. (It should be possible to produce an EBCDIC version of VTL, but we won't talk about that here.) 

If you're running a real operating system, you can use 

man ascii

at the command line to get an ASCII chart. Otherwise, a quick web search can find you one.

Stock VTL doesn't give you separate variables with lower-case names. 

It does give you variables with punctuation marks for names, from exclamation mark to caret, but some, like ? and the digits 0 through 9 are not directly available, and several of the others are used by the interpreter.

The current line number, for instance, is #. Of particular note,

#=1200

is how you jump to line 1200. Note, again, the re-use of the assignment syntax. Or, actually, this is a re-use of assignment itself, but needs some more explanation, later.

(If you are having trouble with VTL-2 bombing or freezing on you, try setting the allocation base and top of RAM variables to zero for now:

&=0
*=0

But if VTL-2 is stable, don't do that. I'll explain later, in the programming introduction.) 

Expressions:

First, let's work through the fundamental VTL expressions. 

  • + is addition,
  • - is subtraction,
  • * is multiplication,
  • / is division (leaving the remainder in the variable %),
  • = in expressions (cough) is comparison for equality,
  • > in expressions is comparison for greater-than-or-equal,
  • < in expressions is comparison for less than, and
  • () nests expressions, overriding the normal left-to-right parse.

Comparisons give you 0 if false, 1 if true, which I will show how to use later. 

All assume 16-bit integer math.

So, let's look at some examples. 

The expression we used as a test up there

?=1+1 

was just adding 1 and 1 and printing the result.

Typing in 

Z=26

sets the variable Z to 26. After that, you can type 

?=Z

and  it prints out the value of Z, 

26

unless you've changed it since then. 

Let's look at comparisons for a moment.

?=Z=26

might cross your eyes, but it will print out 1 for true. It's comparing the value of Z with 26, which is what we just set it to, isn't it?

?=Z<26

will print out 0 for false, and

?=Z>26 

will print out 1 for true - Remember that > in VTL is not just greater than. It's the opposite of <, so it's greater than or equal. (I don't think I'd have done it quite that way, but this is not my toy.) 

Correcting input:

Continuing on,

?=31416/100000

Woops. Too many zeroes. If you tried backspace, you learned that doesn't work. (I think it could be made to work, but I haven't tried.) Unmodified VTL uses an underscore (back arrow on the MC-10 and Color Computer) to cancel single characters of input:

?=31416/100000_

but it does not erase them on the screen:

?=31416/100000_
3
OK

That's a little hard to get used to. 

VTL also let's us cancel whole lines with at-each:

?=31416/100000@

Try it:

?=31416/100000@
OK
?=31416/10000
3
OK

So it divides 31,416 by 10,000 and prints the result. Following that with

?=%

prints the remainder

1416
OK

And that's helpful when you don't have a floating point or other fractional math built-in.

Some limits:

Again, this is integer only, so 

?=3.1416 

gives a result that is hard to explain just yet.

Also, just to warn you in advance, 

31416 / 10000 

without the ?= at the front defines line 31416 containing the invalid expression / 10000 . Which leads us to the fact that there is no line 0, which the authors have turned to advantage.

0

on a line by itself tells the interpreter to list the current program memory -- If you have valid allocation variables for your program memory. 

Valid allocation variables? That's a detour we want to avoid just now.

Back to expressions.

Operator precedence:

The parse is strictly left-to-right, unless you use parentheses. (Again, they are keeping the interpreter simple and the code small.)

So, let's look at something a little complicated. Say we are calculating the area of a circle.

A = πr2

VTL-2 does not have (the last time I looked) exponentiation, so, in VTL-2, that would be 

A=p*r*r

except that we don't have floating point or any other fractional math, so we're going to have to scale it. And p is not pi, so we'll have to get π in there ourselves somehow. 

Suppose we can just throw the fractional part away, and a single fractional digit plus an extra is sufficient:

A=(314*R*R)/100

Try it. Set R to an integer radius and use the expression above.

R=4
A=(314*R*R)/100
?=A

Check it in bc if you have access to bc:

scale=40
pi=a(1)*4
r=4
a=pi*r^2
a
50.2654824574366918154022941324720461471488

(Heh. bc is fun.)

Or check it in a BASIC:

bwBASIC: 10 p=3.1415927
bwBASIC: 20 r=4
bwBASIC: 30 a=p*r^2
bwBASIC: 40 print "Area:", a
bwBASIC: list
     10: p=3.1415927
     20: r=4
     30: a=p*r^2
     40: print "Area:", a
bwBASIC: run
Area:         50.2654832

Okay? (I think bc is more fun.)

Okay. We're somewhat satisfied.

What happens if we leave the parentheses out in VTL? Try it. 

In this case, it works okay going from left to right. In fact, that is exactly what we want -- In this case.

Use of parenthesis:

Let's look at something a little more involved. Say we want to calculate a markup of 50% on a lot of 50 apples and 80 nashi pears. Apples are ¥125 each and nashi are ¥189. (Cheap today.)

A=50
N=80
P=(A*125+N*189)*150/100
?=P

Will this work with just the one set of parentheses? If you guess no, you're right.

397

What happened? Work it left-to-right instead of using the algebraic precedence you worked so hard to remember in middle school or elementary:

50 * 125 is 6250.
6250 + 80 is 6330.
6330 * 189 is 1196370. Woops. That's way too big for 16 bits. 

(You may be wondering, so I'll tell you here. All variables in VTL are unsigned. If you handle negative numbers, you have to handle them by magnitude and somewhere remember that they are negative.)

But go ahead and plug it into VTL anyway. Unless you've got VTL running on a 68000 or some other 32-bit or 64-bit CPU (or written to calculate 32-bit integers on a 16-bit or 8-bit CPU or something), it gives you 16722 to this point, right? 

(Break out bc and subtract 2^16*18 and, oh, 16722 is exactly what it should have given us at this point.)

Okay, 50% is a half, so we should be able to just scale by 2 instead of 100. A and N should still be as we want them, so let's just repeat the expression setting P:

P=(A*125+N*189)*3/2

Oh, but there's something niggling at the back of your mind. It's going to blow up at 6330*189 again. It shouldn't. What's going wrong?

When parentheses don't say otherwise, it's working strictly left to right, right? 

We have to have more parentheses because we have to calculate an intermediate value and VTL does not understand that algebraic precedence business that we spent so much time learning in middle school. (It's like some of the old desktop calculators from decades ago, or like some modern cheap calculators.)

I wonder if it will really work with more parentheses.

P=((A*125)+(N*189))*3/2

Does it give you 32055? 

Okay, I guess it worked. bc says that's what it should give us. But it got close to the limits of 16-bit math in there. (Try each step by hand to watch it get close to blowing up.)

Now we know something about VTL-2 expressions, and have seen some of the limits, and this short description is getting long. Let's save programming for another post.

*** The post on programming is here:
https://joels-programming-fun.blogspot.com/2022/09/short-description-vtl-2-programming-very-tiny-language-pt2.html

1 comment:

  1. Two words: *thank you*! I'm fooling around with VTL-2 on a PAL-1 6502 board and your post has been super-helpful.

    ReplyDelete