CS330 HAL (Hilderman's Algorithm Language)


Highlights of this lab:


Copying and Running HAL9000

If you haven't already done so, you can copy Dr. Hilderman's HAL project into your current directory by typing the following:

cp -r ~hilder/cs330/HALosPublic/ .

Change into this directory, and then you can copy the sample files used in this lab by typing the following:

 cp -r /net/data/ftp/pub/class/330/HAL/nova/ .

When you are inside the HALosPublic directory, you can start the project running by typing: HALstart. The following is an example of starting the project and running some sample code provided:

a049401[42]% HALstart


*********************************************
*               HALos v5.3.6                *
*                                           *
*  Copyright (c) 2018 Robert J. Hilderman.  *
*           All Rights Reserved.            *
*********************************************

HALstart: powering up HAL9000 ...
HALstart: HAL9000 OK
HAL9000: initializing ...
HAL9000: boot sequence started ...
HAL9000: checking clock ...
HAL9000: clock OK
HAL9000: loading HALbios ...
HAL9000: HALbios OK
HALbios: initializing ...
HALbios: checking memory ...
HALbios: memory OK
HALbios: loading HALos ...
HALbios: HALos OK
HALos: initializing ...
HALos: loading HALshell ...
HALos: HALshell OK
HALshell: initializing ...

HALshell> compile nova/helloWorld.hal
HALshell: PID = [1] RETURN_VALUE = [ok] MESSAGE = [nova/helloWorld.hal compiled]
HALshell> nova/helloWorld
Hello World
HALshell> compile halprograms/pass-by-value2
HALshell: PID = [3] RETURN_VALUE = [ok] MESSAGE = [halprograms/pass-by-value2.hal 
compiled]
HALshell> halprograms/pass-by-value2
HALshell> result
HALshell: PID = [4] RETURN_VALUE = [30] 
HALshell> shutdown

HALshell: terminating ...
HALos: terminating ...
HAL9000: powering down ...

A couple of things to note about running the HAL9000 are:


Basic Code Examples of HAL

In this lab, we will look at several examples of Hilderman's Algorithm Language (HAL). This language makes extensive use of a stack. Items are pushed onto the stack using the keyword push, and popped off of the stack using the keyword pop. Generally, items are popped off the stack when instructions are executed. For some instructions like adding, two items are popped off the stack, added together, and the result is pushed back onto the stack. In the section below, we will look at how to display something to the screen and how to add together two integers.

Hello World

comment      :nova/helloWorld.hal
comment      :This program demonstrates how to output a simple message

file         :display

function     :main
open         :display
push         :'Hello World
write        :display
newline      :display
return       :'OK

There are a couple of things to note about this code:

  1. To write to the screen, you have to declare a variable called display (of type file) and open the display. After you have opened the display, any time you write to display, you will be writing to your screen.
  2. Before you write to display, you have to "push" something onto the stack. Notice the line: push :'Hello World. When the write instruction is performed, it will pop whatever is on the stack (in this case, the string "Hello World") and write it to the display.
  3. Be aware that spaces after the colon become part of the value. For instance, these following three examples will be uniquely different in the HAL language

Adding Two Integers

comment      :nova/simpleAddWPrint.hal
comment      :This program demonstrates how adding works with the stack

file         :display

function     :main
open         :display
push         :5
push         :6
add          :
push         :'The results of adding are
write        :display
write        :display
newline      :display
return       :'OK

Notice how the stack is used in this code:

  1. Two operands (5 and 6) are pushed onto the stack.
  2. The add pops the two items off the stack and pushes the result (11) onto the stack.
  3. A message ("The results of adding are ") is pushed onto the stack
  4. The first write pops off and displays the message
  5. The second write pops off and displays the result of the addition

Declaring and Storing Values in Variables

As with all good code, you really should use variables. If you think about how you declare a variable in C++, it might help you remember how to define a variable in HAL.

When you write in C++:
int a;
what information is in that statement? The first thing is that you are declaring an integer; and the second thing is the name of the variable. In HAL, you need two statements to do the same thing:
variable :a
a: integer

If you want a string or a float instead, you can use those keywords in the place of integer.

The following two sample codes show how to create variables. The first sample code shows how to set the value of the variable using the value stored on the stack; and the second sample code shows how to read from the keyboard to store into a variable.

Hard Coded Values

comment      :nova/simpleAddWVar.hal
comment      :This program demonstrates how to hard code values into variables that
comment      :are used for adding

file         :display

function     :main
variable     :a
a            :integer
variable     :b
b            :integer
variable     :c
c            :integer
open         :display

comment      :set a=5
push         :5
set          :a

comment      :set b=6
push         :6
set          :b

comment      :set c=a+b
push         :a
push         :b
add          :
set          :c

comment      :print c
push         :c
push         :'The results of adding are
write        :display
write        :display
newline      :display
return       :'OK

Questions to test your understanding:

  1. How many variables are created in the above code?
  2. What are their types?
  3. How would you set the value of b to 20?

Getting Input from the User

Instead of hard coding the values of a and b, you might want to get input from the user. The following code modifies the previous code.

comment      :nova/simpleAddWInput.hal
comment      :This program demonstrates how to get input from the user,
comment      :store the values in variables and use them for adding

file         :display
file         :keyboard

function     :main
variable     :a
a            :integer
variable     :b
b            :integer
variable     :c
c            :integer
open         :display
open         :keyboard

comment      :ask the user for a
push         :'Please enter an integer value for a
write        :display
read         :keyboard
set          :a

comment      :ask the user for b
push         :'Please enter an integer value for b
write        :display
read         :keyboard
set          :b

comment      :set c=a+b
push         :a
push         :b
add          :
set          :c

comment      :print c
push         :c
push         :'The results of adding are
write        :display
write        :display
newline      :display
return       :'OK

Questions for discussion:

  1. What new file do you have to declare and open to get input from the user?
  2. What happens to the stack when you read?
  3. What happens to the stack when you set the variable?

Creating Functions

You have learned that it is best to break your code down into smaller pieces or functions. We are going to take a look at two code examples of a "sum function" in the following sections. The two examples show pass by value and pass by reference.

In C++, similar functions would be defined with the following prototypes:
int sum(int x, int y);//pass by value
void sum(int x, int y, int &b); //pass by reference

Pass by Value Add Function

comment     :halprograms/pass-by-value2.hal
comment     :this is Dr. Hilderman's sample code: Example 3.12.a.1 

function    :main
variable    :a
a           :integer
push        :10
push        :20
call        :sum
set         :a

comment     :the two integers are still on the stack and need to be popped off
pop         :
pop         :
return      :a

comment     :--------------------------------------------
comment     :In C++, the prototype for this function would be: 
comment     :int sum(int x, int y)

function    :sum

variable    :b
b           :integer

comment     :push the two arguments (sent from main) onto the stack
push        :argument
push        :argument
add         :
set         :b
return      :b

Notice the following:

  1. To send arguments, we push them onto the stack
  2. After our arguments are on the stack, we can call the function (sum)
  3. To define our function, the syntax is: function :sum
  4. To get the two arguments sent from main onto the top of the stack in the sum function, the special syntax is: push :argument
  5. The sum of the two arguments is returned to main. We store the return from the function in the variable a
  6. After the function call in main we have to pop the two arguments off the stack (using pop)

To see the results of this code, we can type "result" in the HAL shell and look at the RETURN_VALUE.

Pass by Reference Add Function

comment     :halprograms/pass-by-reference.hal
comment     :this is Dr. Hilderman's sample code: Example 3.12.b.1 

function    :main
variable    :a
a           :integer
push        :10
push        :20
push        :@a
call        :sum

comment     :the two integers and the address of 'a' are still on the stack pop them
pop         :
pop         :
pop         :
return      :a

comment     :--------------------------------------------
comment     :In C++, the prototype for this function would be: 
comment     :void sum(int x, int y, int &b)

function    :sum

comment     :store the address of 'a' into the reference 'b'
push        :argument
reference   :b

comment     :push the two remaining arguments (sent from main) onto the stack
push        :argument
push        :argument
add         :
set         :b
return      :

Questions for discussion:

  1. How many arguments are pushed onto the stack before the call to the sum function?
  2. What is special about the argument that is pushed on the stack last?
  3. In the sum function, how do we capture the address of a into a variable?
  4. Why don't we have to return b?
  5. In main, why are there three pop's?
  6. How do we see the results of this code?

Looping and If/Then

Looping in HAL involves three things:

  1. A comparison. It can be one of the following:
  2. A label of a place where you want to jump to. For instance, Tip: each label should have a unique name. For instance, you cannot use the same label in a function that you used in main. Strange things happen!
     
  3. A jump statement (this will remind you of good old Assembly). Yes, spaghetti code you can make!

Behind the scenes, the compare operation sets a COMPARISON_STATUS_FLAG; the jumpless, jumpequal, and jumpgreater look at the value of that flag to determine whether it should jump or not. Refer to the HAL Operating System Manual for more details on the COMPARISON_STATUS_FLAG.

The following three code segments give examples of:

  1. A count controlled "while" loop
  2. An "if" statement that checks for values less than or equal to zero
  3. An "if" statement that checks whether the input is a floating point value

Count Controlled "While"

comment      :nova/whileExample.hal
comment      :This program loops 5 times inputting and adding 5 floats

file         :display
file         :keyboard

function     :main
variable     :inF
inF          :float
variable     :sum
sum          :float
variable     :count
count        :integer

open         :display
open         :keyboard

comment      :initialize count and sum
push         :0.0
set          :sum
push         :0
set          :count

comment      :Prompt the user 5 times for input summing values as you go
label        :loop
push         :'Please enter a floating point value
write        :display
read         :keyboard
set          :inF

comment      :sum=sum+inF
push         :sum
push         :inF
add          :
set          :sum

comment      :count=count+1
push         :count
push         :1
add          :
set          :count

comment      :while count<5, continue looping
push         :count
push         :5
compare      :
jumpless     :loop

push         :sum
push         :'The sum of the 5 floats is:
write        :display
write        :display
newline      :display
return       :'OK

The code above has three variables:

  1. inF
  2. sum
  3. count

Notice a couple of things about this code:

  1. After sum and count are initialized to zero, a label is created using the syntax: label :loop

  2. After incrementing count, a compare statement is used to compare the two items on the stack (count and 5).

  3. If count < 5, the jumpless :loop statement will set the instruction pointer to the statement labeled loop. Notice the order that the items count and 5 are pushed onto the stack.

If Value Is Less Than or Equal to Zero

The code segment below makes use of the whileExample.hal code from above. The section between the dotted segments is an added "if" statement, which checks if the input value is less than or equal to zero. If it is, then an error message is printed and the negative value is not added to the sum. Examine the code below to see how it works:

comment      :nova/whileIfExample.hal
comment      :This is the same as whileExample.hal except there is an if statement

Missing in this code segment:
                    declare variables: "inF", "sum", and "count"
                    open "keyboard" and "display"
                    initialize "count" and "sum" to zero
                    create a "loop" label
                    ask the user for input
                    read from the keyboard and store it into "inF"
...........................................................................

comment      :if input is less than or equal 0, then display an error message
push         :inF
push         :0
compare      :
jumpgreater  :continue
push         :'You cannot enter 0 or negative values, please try again
write        :display
newline      :display
jump         :loop

label        :continue
comment      :sum=sum+inF
push         :sum
push         :inF
add          :
set          :sum
...........................................................................
Missing in this code segment:
                    increment count by one
                    if count is less than five, jump to "loop" label
                    otherwise, display the sum of the five floats

Notice:

  1. You use jumpgreater to skip over the error message and continue as before in the code (reverse logic from what is written in comments)
  2. If the value in inF is less than or equal to zero, then an error message is displayed; and you jump back to the loop (asking for another float).
  3. The count and sum are not affected if a negative or zero float value is entered.

If Value Is Not the Right Type

The code segment below makes use of the whileExample.hal code from above.. The section between the dotted segments is an added "if" statement, which checks if the input value is not a float. If the input is not a float, then an error message is printed and the input is not stored in inF. Examine the code below to see how it works:

comment      :nova/whileIfFloat.hal
comment      :This is the same as whileExample.hal except there is an if statement

Missing in this code segment:
                    declare variables: "inF", "sum", and "count"
                    open "keyboard" and "display"
                    initialize "count" and "sum" to zero
                    create a "loop" label
                    ask the user for input
                    read from the keyboard
...........................................................................

comment      :if input is not float display an error message
compare      :float
jumpequal    :continue
push         :'You did not enter a float, please try again
write        :display
newline      :display
jump         :loop

label        :continue
set          :inF
comment      :sum=sum+inF
push         :sum
push         :inF
add          :
set          :sum
...........................................................................
Missing in this code segment:
                    increment count by one
                    if count is less than five, jump to "loop" label
                    otherwise, display the sum of the five floats

Questions:

  1. What is compare :float comparing? Does it pop value(s) off the stack?
  2. In what situation will jumpequal :continue set the instruction pointer to the address of the continue label?
  3. There is a bug in this code segment with regards to the stack. What is the bug?

Arrays

Sometimes you might want to store your data into an array. You can have arrays of integers, floats, and strings. The syntax to declare an array of five integers is:

variable     :a<5>
a            :integer

It is pretty close to declaring a plain old integer. You simply add the size of the array after its name in <> brackets. When you want to work with the individual elements of the array, the syntax is a<i> (where i is some variable or integer in the range of 0 to 4)

comment      :nova/arrayInputOutput.hal
comment      :This program demonstrates how store and display values in an array
comment      :The input into the array is from elements 0 to 4
comment      :The output from the array is from elements 4 to 0

file         :display
file         :keyboard
constant     :NUM
NUM          :integer

function     :main
push         :5
set          :NUM
variable     :a<5>
a            :integer
variable     :i
i            :integer

open         :keyboard
open         :display

comment      :input values into the array from the user
comment      :Step 1 initialize i
push         :0
set          :i

comment      :Step 2 get input from user and store it in the array
label        :inputLoop
push         :'Please enter an integer value
write        :display
read         :keyboard
set          :a<i>

comment      :Step 3 increment i
push         :i
push         :1
add          :
set          :i

comment      :Step 4 while i is less than NUM, continue looping
push         :i
push         :NUM
compare      :
jumpless     :inputLoop

comment      :display the values stored in the array in reverse order
push         :'Values entered are:
write        :display
newline      :display

comment      :Step 1 initialize i
push         :NUM
set          :i

label        :outputLoop
comment      :Step 2 adjust i so it is: i=i-1
push         :i
push         :1
subtract     :
set          :i

comment      :Step 3 display one element of the array
push         :a<i>
write        :display
newline      :display

comment      :Step 4 while i is greater than 0, continue looping
push         :i
push         :0
compare      :
jumpgreater  :outputLoop
return       :'OK

This code is quite long because it gives you a sample of two for loop's with ranges from 0 to 4 and from 4 to 0.

A couple of things worth noting:

  1. the constant NUM cannot be used in the place of the 5 when you are indicating the size of the array
  2. push's and set's must be done in main. In other words, you cannot set the global constant NUM above main
  3. notice the syntax of accessing an element of the array using the variable i inside angle brackets
  4. pay attention to the order that values are pushed on the stack:
    1. before the compare operation to check if i < NUM
    2. before the subtract operation to perform i - 1
    3. before the compare operation to check if i > 0

Reading and Writing Files

You will find that working with files is similar to working with the keyboard and display. Here's a review of reading from and writing to the terminal:

  1. declare a "file":
    file :display
    file :keyboard
  2. open the file that you have declared:
    open :display
    open :keyboard
  3. read or write to the terminal:
    write :display
    read :keyboard

The following code is an example of reading and writing files.

comment      :halprograms/filetester6.hal
comment      :this is Dr. Hilderman's sample code: Program 4.3
comment      :This program copies the contents of one file to another.

function     :main
file         :a
a            :input
push         :'halprograms/crapolaIN1
set          :a
file         :b
b            :output
push         :'halprograms/crapolaOUT1
set          :b
open         :a
open         :b
label        :continue
read         :a
compare      :eof
jumpequal    :end
write        :b
newline      :b
jump         :continue
label        :end
close        :a
close        :b
return       :'OK

Questions for discussion:

  1. How is the code similar to working with the display and keyboard
  2. How is the code different? (at least 2 things)
  3. How do you check for the end of the file?
  4. Normally, when you do a compare, what happens to the stack? What happens to the stack, in this case?

Note: before you run this code, check to make sure that crapolaIN1 is in the halprograms directory. If it isn't, you will have to create it.


Working with Command-line Arguments

Sometimes you may find it useful to send arguments on the command-line. That means: when you type the name of the program, you also can type additional information.

The following example modifies the previous section's code by using the command-line arguments instead of hard coded filenames.

comment      :nova/commandLine2.hal fileIn fileOut
comment      :This program copies the contents of one file to another.
comment      :Instead of hard coding the filenames, the names come directly
comment      :after the program name (as command-line arguments)

file         :display

function     :main
file         :a
a            :input
file         :b
b            :output
push         :argument
set          :b
push         :argument
set          :a
open         :a
open         :b
label        :continue
read         :a
compare      :eof
jumpequal    :end
write        :b
newline      :b
jump         :continue
label        :end
close        :a
close        :b
return       :'OK

When you run this code, you will have to specify the input and output files after the name of the program. If you do not specify a path, these files need to be in the HALosPublic directory.

Notice the following

  1. the syntax:
    push :argument
    to have the arguments pushed onto the stack.
  2. the order of the arguments on the stack. Specifically, is fileIn or fileOut pushed onto the stack first?

References