Skip navigation

I spend a little while adding something called protected mode to shogun. What is it? Well, it disables all external functions except those that deal with basic output. Why did I do this, you ask? Well, I did it so I could implement the testing grounds.

I wrote some horrid php and html to bring this about. You can now test out shogun online on my server by heading to http://shogun.dev.redxdev.com/.

The limitations of running on this environment are as follows:

  • shoasm has a limited runtime of 5 seconds
  • shogun has a limited runtime of 5 seconds
  • shogun has a maximum virtual memory allocation of 1024
  • shogun can use at most 1024 bytes of data
  • shogun runs in protected mode

If you don’t want to build shogun yourself, then head over to the testing grounds!

Linode, the host for the VPS this website runs on, just gave out free upgrades that double the amount of ram on your system (as part of a larger move to new hardware). As a result, I can now afford to run Jenkins CI on this VPS! I’ve set up the server at http://ci.redxdev.com/, and you will find that Shogun is now building there.

I have released Shogun 0.1.7 on bitbucket! This time, I’ve packaged both windows and linux binaries. You can find all of this at https://bitbucket.org/redxdev/shogun/downloads.

UPDATE: I suggest building from the repository instead of using binaries. There was a major problem with the GTEQ opcode in 0.1.7, which has been fixed in the repository.

UPDATE 2: I found an interesting side effect of memory allocation! In C/C++, if you define a pointer but don’t assign it anything, then it is likely that you will crash your program if you try to access it. Similarly, if you allocate memory in Shogun but don’t assign it anything, internally it is represented by a NULL pointer, making it so that operations on it will crash. Unfortunately, the VM doesn’t check whether a pointer is null so that it can give a proper error message. Instead, it tries to operate on that NULL pointer, and gets a segfault instead. This issue is being worked on, and you can track its progress here: https://bitbucket.org/redxdev/shogun/issue/21/fix-segfaults-when-trying-to-use.

Oh man! Well, this is embarrassing. I just started making a makefile for Shogun on Linux, and there is a huge amount of errors that pop up. I forgot that there are some pretty annoying differences between GCC and MSVC. For example, MSVC couldn’t care less about what you throw in a function, but GCC cries about throw() declarations not matching up in derived classes.

I’ll hopefully have this fixed soon.

UPDATE: Currently this issue is on hold, as apparently stdlibc++ doesn’t fully support <regex> yet, and I don’t want to rely on Boost if I can help it. For more information, see https://bitbucket.org/redxdev/shogun/issue/20/fix-the-errors-that-appear-when-compiling

UPDATE 2: This issue has been fixed! I decided to go with Boost after all, but only on gcc. Anyone who wants to build with GCC needs to place the boost distribution inside the deps folder and build boost.

Welcome to part 4 of the shogun tutorial series! If you haven’t already, please ready parts 1, 2, and 3.
In the last tutorial, you learned how to access memory. The problem with memory is that you always have to reference positions by a number. That doesn’t exactly do much for code readability. To remedy that, you can use variables!

Variables and You

Start by running this:

main:
  alloc 1
  store 0 "Hello World!"
  load 0
  call print
  end

You should recognize this from the last tutorial. Let’s play with it and add a variable.

var $foo

main:
  store #foo "Hello World!"
  call print $foo
  alloc 0
  end

Start with the first line. Here, I introduce a new operation to us: VAR. It isn’t really an operation (only the assembler actually has code to handle it; running VAR in the virtual machine will error), but it is used as one. VAR defines a variable, in this case foo. The $ preceding the variable name marks it as a variable (I know some people who hate PHP will kill me for this, but with the way the parser is implemented I needed something to precede variable names). VAR operations should always go before the rest of your code due to reasons I won’t explain here.

Moving on to line 4, we come to the STORE operation. This time, instead of an address, we give #foo. I’ll go into why we use the # instead of a $ later.

Notice that we then jump right into the CALL operation on line 5, no LOAD needed! Ah, the beauty of variables.

Finally, we deallocate and end. You might be wondering why I deallocate even though I never allocate, and you’ll find out in a bit, but first…

Operators

I’ve introduced here two new operators: $ and #. As I’ve stated, the $ precedes variables. This is true, most of the time. The $ operator is what I call the variable data operator. It retrieves and pushes the data held inside the variable onto the stack. Unfortunately, that won’t work for an operation that takes a memory address instead of the data itself, such as the STORE operation. That is why we have the #, or variable position operator. It pushes the address of the variable onto the stack (or just stores it into the argument list, depending on the type of operation).

How it Works

Variables can be thought of as aliases for memory addresses, except that you don’t need to allocate space for them. In fact, variables use the same exact memory that STORE and LOAD use (a side effect of which allows the VM to know nothing about how variables are implemented). The assembler writes the amount of space reserved for variables into the binary header when you run shoasm. It also replaces all instances of variables with LOAD statements or addresses, as needed.

A side effect of this method is that you can deallocate memory used for variables. Be careful of this, as you will get a standard memory not allocated error if you try to use a variable after deallocating it (therefore making it incredibly hard to debug).

Another Operator

Because variables use the same memory space as STORE/LOAD, they can also cause trouble.

Try running this:

var $foo

main:
  alloc 1
  store #foo "Bar"
  store "Baz" 0
  load 0
  call print
  call print $foo
  alloc 0
  end

What you might expect to see is this:

Baz
Bar

While you will really get this:

Baz
Baz

Why? Because the compiler recognizes the variable foo and assigns it the first open memory position: 0. In the script, you first store “Bar” to foo and then overwrite it by STORE-ing to position 0.

How do we avoid this problem? A new operator! The @, or memory operator, gives you the end of the memory used by variables. It is used like so:

... @0 ; Get the first position in memory that isn't used by variables
... @1 ; Get the second
... @-1 ; Get the last position in memory used by a variable (note that if you have no variables an error will be thrown, as this will return memory address -1).

Note that you will have to use an ALLOC operation to allocate memory:

alloc @10 ; Allocate 10 extra spaces in memory not used by variables

Conclusion

After reading this tutorial, you probably won’t use standard ALLOC/STORE/LOAD for a while, or at least until you get into more complex programming. You know how to create and use variables, which should make things much easier (though you may have to get used to the # and $ operators). Until next time!

Welcome to my Shogun tutorial series! If you haven’t already, read part 1 and 2 before reading this!

Remember remember…

You should now be able to save things in Shogun by using the stack, but what if you want an easier, more permanent solution to storing data? Welcome to the land of memory! Memory in Shogun is much the same as memory in computers, with a few minor differences. Memory addresses are specified as integers, and each address stores one piece of data. Where is the difference? The data itself! There are actually two main differences. The first is that data in Shogun is dynamically typed, meaning that Shogun will convert numbers to strings to booleans and back again as needed. The second difference is that a single piece of data takes up one spot in memory. While a float in C++ might take up 32 bits in memory, a number in Shogun will take up one spot in memory. Each spot in memory can actually be of a variable size.

How do we access this memory? Well, try running the following:

main:
  alloc 1
  store 0 "Hello World!"
  load 0
  call print
  alloc 0

Let’s look through this. The second line calls the allocate operation, which allocates one place in memory in this case. ALLOC actually allocates and deallocates memory (to deallocate, just pass a number that is smaller than the amount of currently allocated memory).

The third line is where we store some data. The STORE operation takes data and stores it in the specified memory address (indexed by 0). The data will stay in that address until you either change it or deallocate it.

The fourth line retrieves the data from the specified memory address. Remember that retrieving data from the stack also removes it from the stack; this is not the case with memory. Even after retrieving the data, a copy remains at the same address.

The sixth line is another allocation statement, this time deallocating all memory (ALLOC 0 will always deallocate all memory). While you don’t need to do this, it is good practice. Even after running an END operation, memory isn’t deallocated until the virtual machine object is destroyed, so if you know that you won’t be using any data in memory again, then you should run ALLOC 0.

Conclusion

This was a really short tutorial, but I’ve decided that a lot of short ones is probably better than a few long ones. It also makes it easier for me to write them.

Move on to part 4!

Welcome to part two of the Shogun tutorial series! If you haven’t read it yet, go look at part one.

The Stack

Let’s get into some of the internals of Shogun, and find out how they affect us. First up: the stack!

Shogun is a stack-based virtual machine, as opposed to a register-based one. What does that mean? Well, almost all CPUs are register machines (including the one in your computer). Register machines have, in addition to memory space to store data, a few select areas that they can store other data for fast access, called registers. Most operations in register machines operate on these registers. Shogun, however, uses the stack approach.

Instead of a limited set of spaces to store data, Shogun has a ‘stack’ of space to store data in addition to memory. Internally, it is represented as a dynamic list (actually a deque as of this writing), but only two functions are exposed to scripts: pushing and popping.

First, think of the stack like a stack of papers on your desk (if you don’t have a desk, then tough luck). If I push onto the stack, I am placing a new piece of paper (data) on top of the stack. If I pop the stack, then I am taking a piece of paper off of the stack.

In fact, push and pop are the names of the commands you use! Let’s try them out. Throw this together:

main:
  push 1
  push 2
  add
  call print

What do you think that will output? Go ahead and run it through shoasm and then shogun. You should get an answer of 3. How did that work? Well, the 1 and 2 obviously were added together, but let’s talk about exactly how that add command works.

First, you push 1 and two onto the stack. The stack now looks like this:

2
1

Where the 2 is on top (and hence if we run pop, the 2 will be removed). After running the two pushes, the add operations runs. It pops twice to get two operands, and then adds them together. Finally, the call operation runs print which then pops the result of add and prints it.

Now try running this:

main:
  add 2 1
  call print

You should get the same answer of 3! What happened to the push statements? Well, this is where we talk about some syntactical sugar that the assembler gives us.

Sugar of the Syntax

Writing push statements all the time is fairly annoying, so the assembler takes away the trouble by allowing you to specify arguments inline. You’ve already been doing that for the call operation, even if you haven’t realized it. In reality, the assembler actually converts these inline arguments and inserts the push operations for us!

Try running this code:

main:
  dump
  add 2 1
  call print

You should get something like so:

-------
ShogunVM 0.1.6 (binary 9) dump
Constant Table:
[0:12345678] = "print"

Instruction List (pointer @ 0):
[0] = DUMP
[1] = PUSH 1
[2] = PUSH 2
[3] = ADD
[4] = LOADK 0
[5] = CALL

Stack:

Memory:

End of Dump
-------
3

Whoa! A dump has appeared in front of us! If you haven’t guessed already, dump will have Shogun print the current state of the virtual machine to console. Let’s see what each part means.

Those first few lines give us Shogun’s version (and the binary version) and tells us what is in the constant table. What is this constant table, you ask? Well, it holds any value that isn’t a number. I’ll talk about why we need that later.

Take a look at the highlighted section in the middle, the one labeled “Instruction List”. That first line tells us that the pointer is at 0. That means that the instruction at 0 is about to be executed. Now, look at the list of instructions and compare it to your code. The first instruction is right, but after that it isn’t!

The assembler pulled a fast one on us. It converted add 2 1 into two push statements! Not only that, but it reversed the operands! Something must be wrong! No, that is correct. Remember, whatever is pushed last onto the stack is popped first, so you have to push arguments in reverse order (don’t believe me? replace add with sub and try it yourself).

List v. Stack

Now, someone who looks carefully may notice that push breaks the rule of popping from the stack! Well, yeah, it is because there has to be some way to get items on the stack without removing them first, but that isn’t the only reason. There are actually two types of instructions: list-based, and stack-based.

Stack-based instructions are what we’ve been talking about; they pop arguments from the stack. List-based instructions take their arguments instead from an argument list that is written with the instruction in the binary. Arguments for list-based instructions can’t be taken from the stack, and as such must be specified during compile-time. Side-note: this also prevents variables from being used in list-based instructions, but we’ll get to that in a later article.

Conclusion

That’s it for part two. If you want an exercise to work on yourself, try making a simple adding calculator that asks for each operand, then adds them. Hint: To read from console, use call readline. It will push whatever is typed on a line onto the stack.

Click here for part 3.

I’ve decided to make a short tutorial series on using Shogun. I might extend at some point to even include embedding shogun. For now, here is the first part of the tutorial.

First of all, you have the choice of building Shogun yourself or downloading binaries. To build it yourself, you will need a modern C++ compiler, so probably MSVC or GCC. You can get the code by cloning the repository. Right now there are only Visual Studio projects available to build Shogun, but it should be simple enough to build it on a linux system.

As of this writing, only Windows binaries exist for Shogun, but others may be put up at some point. You can get all of them here.

For this tutorial, you will need the shoasm and shogun programs. They are command-line applications that assemble and run your code, respectively.

Hello World!

For your first program, we will be writing the classic hello world program! Start by opening up a blank text document (I’m assuming it is named hello-world.svm). Let’s start with the basic syntax of ShoASM. The most basic things you can have in ShoASM are operations or opcodes, which look like this:

foo bar baz

Where foo is the operation, and bar/baz are arguments. foo isn’t actually an operation, so don’t put that into your script. Arguments can be anything from strings (which are set off by quotes, unless they are only alphanumeric) to numbers (integers or decimals) to booleans (any capitalization of true/false). In fact, those are all the data types that Shogun supports, save two (userdata and nil, but we’ll talk about those another time).

Next, we have labels. Labels can be used to control the flow of the program. We’ll talk about how to use them later, but for now here is what they look like:

foo:
  operation bar baz

Finally, we have comments:

foo bar baz ; Hi! I'm a comment!

Why don’t we start writing our first program? Put this into your script:

main:
  call print "Hello World!"
  end

Save it, then run the following in a command console:

shoasm -i hello-world.svm -o hello-world.sho

You should see something such as the following:

=== Begin ShogunVM Assembly ===
Opening input file "hello-world.svm" for reading...
Tokenizing input...
Parsing input...
Opening output file "hello-world.sho" for writing...
Compiling...
=== Finished ===

If you find any errors, make sure you copied the code correctly. What we did here is we ran the Shogun assembler tool (shoasm) to compile our script file (.svm) into a Shogun binary (.sho). Now we just need to run it! Run the following in a command console:

shogun hello-world.sho

Here we run the Shogun virtual machine, telling it to take our now-compiled script as input. If everything works, you should see a nice ”Hello World!” come up. Now, why don’t we take a look at what we did?

main:
  call print "Hello World!"
  end

That first line is a label. We called it main, because it holds the code that runs first. A main label isn’t required, but it is considered good practice to have. Note that the virtual machine will run whatever code comes first, regardless of label.

main:
  call print "Hello World!"
  end

Here, we run the operation call. This operation runs a function that has been registered with the virtual machine in C++. At the time of this writing, the only standard functions are print and readline (thought this will change in the future). call takes one or more arguments, the first being the name of the function and the rest being arguments to that function. In this case, we call print with the argument “Hello World!”.

main:
  call print "Hello World!"
  end

Last but not least, we come to end. This operation halts the operation of the virtual machine. It isn’t required that all programs end in end, but it is considered good practice.

Conclusion

That’s it for the first tutorial. If you would like to take a look at the list of operations, you can check the project wiki here. As of this writing, it is up to date with Shogun version 0.1.6. Most operations use concepts I have not yet talked about, so don’t fret if you don’t understand how most operations work.

If you would just like to check out the project in general, see the project page on bitbucket.

You can move on to part two of the series here.

Shogun has been updated in the repository. There is now support for variables!


var $count

main:
  store $count 10
  call print "Countdown:"
  goto loop

loop:
  call print $count
  sub $count 1
  store $count
  eq $count -1
  goto end
  goto loop

end:
  call print "Done!"
  alloc 0
  end

I wanted to start fresh, and to that end I reset the posts on this site. I’m starting over, doing new projects, fixing old ones. More importantly, I have a project I’m releasing called Shogun.

Shogun is a stack-based virtual machine and assembler. Shogun is general-purpose and lightweight, requiring little to no dependencies to build and run. The assembly language is fairly simple to understand. For example, here is a program that counts down from 10:

; Adapted from scripts/asm/countdown.svm
; Simple Countdown

main:
  alloc 1 ; Allocate some memory
  call print "Countdown:"
  call print 10
  push 10
  goto loop

loop:
  store 0 ; Store the current number in memory
  load 0 ; Need to load it onto the stack again, as store pops it off of the stack
  add -1
  store 0
  load 0
  eq -1 ; If the number is -1
  goto stop ; Then goto stop
  load ; Else...
  call print ; Print the number
  load 0
  goto loop ; Loop!

stop:
  alloc 0 ; Deallocate memory
  end ; Done!

Even throughout that program, the assembler makes a lot of optimizations and uses a bit of syntactical sugar. I’ll explain all of this in an upcoming article. In the meantime, you can check out the project repository at BitBucket.

Shogun is a learning experience for me more than anything, but if it helps you or you decide to contribute, then all the better!