Chapter 13. Advanced Subjects

This chapter will cover some miscellaneous and advanced topics not yet mentioned. This includes command line arguments, numerical bases, bitwise operations, events, and labels/gotos.

13.1 - Command Line Arguments

Command line arguments are parameters passed to an application at invocation. You have already used command line arguments when starting the Hassium interpreter from the command line. The syntax is hassium <filename>. <filename> is a command line argument given to the Hassium application that tells it where to find the source file. Run hassium --help for a list of the command line arguments the Hassium interpreter can take.

Your Hassium program can take it's own command line arguments. To do this, the main method needs to be declared to take a single list parameter. It is best practice to name this parameter args. Here is an application that prints out whatever arguments it is given. We'll agree to save the source for the following program in args.has for testing.

source.has:

func main (args : list) {
    foreach (arg in args) {
        printf ("Argument: {0}\n", arg);
    }
}

Run the command: hassium args.has -b data --this-is-an-argument moreData

Output:

Argument: -b
Argument: data
Argument: --this-is-an-argument
Argument: moreData

Let's make a useful program that uses command line arguments. If you have played around with the terminal you have more than likely taken notice of the cat command. cat takes a file path and displays the text inside that file. Run cat args.has to test this. Let's implement cat in Hassium.

from IO use FS;
from Util use OS;

func main (args : list) {
    if (args.length <= 0) {
        println ("Please provide at least one path!");
        OS.exit (1);
    }
    foreach (arg in args) {
        if (!FS.exists (arg)) {
            printf ("{0} does not exist!\n", arg);
            continue;
        }
        printf ("{0}:\n", arg);
        println (FS.readstring (arg));
    }
}

The program starts by making sure at least one file argument was given. If no arguments were given, there is nothing to display, so the program displays an error and exits with status code 1. From there, the program loops through the arguments, checking to see if the file actually exists. If the file does not exist, an error message is displayed and the program continues on. If the file does exist, it's path is displayed, followed by the contents of that file.

13.2 - Numerical Bases

In all of the code examples up until this point, the number literals have all been in base 10. Base 10 is the standard English method of writing numbers, using the symbols 0 through 9 to represent them. Hassium also supports base 2 (binary), base 8 (octal), and base 16 (hexadecimal) numbers. These numbers are not different in value from each other, only in the way that they are notated.

13.2.1 Base 2 - Binary

Binary numbers are represented using 0 and 1. The number is counted from right to left, if the first value is 1, that number is added to the total. The values for each place double as we move from right to left. Each place in a binary number is called a bit, eight bits make one byte.

Here is the number 49 represented in binary notation (as a byte): 00110001. Starting from the right, the first bit is a 1, adding 1 to the total. The next bit doubles the possible value to 2, but the bit is a 0. The next two bits then double this again from 4 to 8. Then there is a bit set to 1 which adds 16 to the total, making it 17. Following this is the last 1 bit, which adds 32 to the total, making it 49.

To indicate a binary literal in Hassium, you must prefix the 0s and 1s with 0b. Try the following program.

func main () {
    println (49);
    println (0b00110001);
}

Output:

49
49

13.2.2 Base 8 - Octal

The octal number system uses the numbers 0 through 8 to represent numbers. Each place starting from right to left represents that number multiplied by 8 to that place.

Here is the number 49 represented in octal: 61. Starting from the right, the number 1 is multiplied by 8^0, which is 1. Then 6 is multiplied by 8^1, which is 48. These two numbers are then added up for a total of 49.

To indicate an octal literal in Hassium, you must prefix the numbers with 0o. Try the following program.

func main () {
   println (49);
   println (0o61);
}

Output:

49
49

13.2.3 Base 16 - Hexadecimal

The hexadecimal number system uses values of 1 through 15 in each place. Because there are no individual numbers that can represent values of 10 or higher, the hexadecimal system uses the characters A through F to represent the values 10 through 15.

Here is the number 235 in hexadecimal: EB. The first number B represents the value 11, which is multiplied by 16^0, resulting in 11. This is then added to the number E (representing 14), which is multiplied by 16^1, resulting in 224. These two numbers are added together to result in ``235.```

To indicate a hexadecimal literal in Hassium, you must prefix the numbers with 0x. Try the following program.

func main () {
    println (235);
    println (oxEB);
}

Output:

235
235

13.3 - Bitwise Operations

Bitwise operations refer to the manipulation of bits in a data structure. This can be from certain operators that operate on bits or by directly manipulating individual bits.

13.3.1 Bitwise - And

The & (bitwise and) binary operator checks each bit on both operands. If both bits are 1, the resulting bit will be 1. If one bit is 1 and the other is 0, or both bits are 0, the resulting bit will be 0.

01100110
&
11010011

01000010

13.3.2 Bitwise - Or

The | (bitwise or) binary operator checks each bit on both operands. If one or both bits are 1, then the resulting bit will be 1. Only if both bits are 0 will the resulting bit also be 0.

01100110
|
11010011

11110111

13.3.3 Bitwise - Xor

The ^ (bitwise xor) binary operator checks each bit on both operands. Only if one bit is 1 and the other bit is 0 will the resulting bit be 1. If both bits are 0 or both bits are 1 will the resulting bit be one.

13.3.4 Function - getbit

The getbit function is an attribute of the int and char types. It returns a bool indicating the value of the bit in question. Try the following code.

func main () {
    char j = 49.tochar ();

    for (int i = 0; i < 7; i++) {
        print (j.getbit (i).toint ());   
    }
}

Output:

0100011

13.3.5 Function - setbit

The setbit function is an attribute of the int and char types. It modifies the bit at the given position to the given value. Try the following code.

func main () {
    int i = 44;
    println (i);
    i = i.setbit (0, true);
    println (i);
}

Output:

44
45

13.4 - Events

In Hassium, and event is a list of functions that trigger all at once based on a condition. This is usually used in conjunction with a separate thread which checks the event condition. For example, this might be used on a chat application where an event fires on a message received.

13.4.1 Events - Declarations and Handlers

Events instantiate using the global Event constructor. The constructor takes in functions that will be called when the event fires. For 13.4, we will be developing an example application that counts from 0 to 100, 000, triggering an event each time a multiple of 1, 000 is reached.

func main () {
    Event multiplereached = new Event (onmultiplereached);
}

func onmultiplereached (n : int) : null {
    printf ("Multiple reached: {0}\n", n);
}

13.4.2 Events - Triggering

To trigger an event, call the Event.fire function. The arguments inside the fire function call will be the arguments passed to each handler function. For the program we are creating, the main method should loop, firing the event each time there is a multiplt of 1, 000.

func main () {
    Event multiplereached = new Event (onmultiplereached);

    for (int i = 0; i < 100, 000; i++) {
        if (i % 1000 == 0) {
            multiplereached.fire (i);
        }
    }
}

func onmultiplereached (n : int) : null {
    printf ("Multiple reached: {0}\n", n);
}

Output:

0
1000
2000
3000
4000
...

13.5 - Labels and Gotos

In programming, a label marks a certain section of code that can be jumped to. A goto is a statement that jumps to a label. This practice almost always discouraged. Before using a label/goto, you should read this article (http://www.u.arizona.edu/~rubinson/copyright_violations/Go_To_Considered_Harmful.html). The one time that a label and goto is considered acceptable is when breaking from a nested loop.

Let's create a loop using labels and gotos. This will count up from 0 to 15.

func main () {
    int counter = 0;

    loop:
    counter++;
    println (counter);
    if (counter < 15) {
        goto loop;
    }
}

The first line of main starts by initializing the counter to 0. The third line declares the label, named loop. When this is encountered it does nothing by itself. The fourth and fifth lines increment counter and display it to the terminal. main finishes off by checking if counter is less than 15. If this is true, the program will jump to the location of loop, repeating the process.

Chapter 13 - Exercises

Exercise 13.1

Without use of a computer, calculate the result of the following operations.

0xF3B + 0o32 - 0b11001101 = ?
0x33 * 0o434 = ?
11 + 0b11 + 0x11 + 0o11 = ?

Exercise 13.2

Without use of a computer, calculate the result of the following operations.

32 | 45 = ?
0b00101110 ^ 0b01000111 = ?
78 & 34 | 0b11010111 = ?

Exercise 13.3

Create a program that acts like the grep command. The first command line argument should be the file path, and the second should be the search term. The program should stream read through the given file, if the line contains the search term, that line is printed to the terminal.

Exercise 13.4

Write a program that counts infinitely using labels and gotos.

results matching ""

    No results matching ""