{"id":882,"date":"2014-10-21T15:06:52","date_gmt":"2014-10-21T15:06:52","guid":{"rendered":"http:\/\/www.visionriders.com\/blog\/?p=882"},"modified":"2014-10-21T15:07:09","modified_gmt":"2014-10-21T15:07:09","slug":"a-five-bit-scripting-language","status":"publish","type":"post","link":"https:\/\/www.visionriders.com\/blog\/2014\/10\/a-five-bit-scripting-language\/","title":{"rendered":"A Five Bit Scripting Language"},"content":{"rendered":"<p>Last night in bed, as I was thinking about things that still need to be done for my next game before I can really start diving into it, I began thinking about the scripting engine. <cite>Another Star<\/cite> just hard-coded all scripting in C#, but, for one, there&#8217;s no way I&#8217;m scripting scenes in C++, and two, it&#8217;s <em>really<\/em> tedious to hard code script even in C#.<\/p>\n<p>As I thought about the scripting language and how I could store all the script in files, I came up with the idea of packing all the scripts in one file. In the file header would be a table of all the individual scripts with their locations and sizes within the file, so I could load only what I need at a time.<\/p>\n<p>And, since I want the language to be case insensitive anyway, I figured I could probably save some space by reducing each character to just six bits. Six bits gives enough for only a subset of ASCII. 64 characters, to be exact. And you want to convert lowercase letters to uppercase letters (or vice versa) so you don&#8217;t waste an extra 26 of those precious characters on just letters. With six bit characters, you can do what&#8217;s called packing. This is a form of data compression where you shove four six bit characters into three bytes, where normally each ASCII character would need a full byte each. Reduces the file size by exactly 25% right off the bat. Well, not counting the file header and such, but that&#8217;s only a minute portion of the file.<\/p>\n<p>Granted, there&#8217;s really no <em>need<\/em> to save 25% by compressing a text file. I mean, really now. It&#8217;s highly unlikely that all the scripts in the entire game combined together will amount to much more than a megabyte or two, if even that. But it&#8217;s something I could do if I wanted to, nonetheless.<\/p>\n<p>Then, I began to wonder if I could compress it even further. Five bytes per character! Eight characters would fit into every five bytes! Mwa, ha, ha, ha! I&#8217;m a madman!<\/p>\n<p>Thing is, it can be done, and it can be done without a lot of &#8220;shifting&#8221; like in old-timey standards such as <a href=\"http:\/\/en.wikipedia.org\/wiki\/Baudot_code\">Baudot code<\/a>.<\/p>\n<p><!--more Click here to continue reading and find out how!-->Let&#8217;s take the following code as an example. This is how it might be written in the source code file:<\/p>\n<p><code>function Example<br \/>\n&nbsp;&nbsp;&nbsp;let int $foo=15<br \/>\n&nbsp;&nbsp;&nbsp;if $foo != 15 then<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$foo=20+196<br \/>\n&nbsp;&nbsp;&nbsp;endif<br \/>\nendfunction<\/code><\/p>\n<p>Ignoring for the moment that the example code is redundant and accomplishes absolutely nothing ($foo will always be 15 since we just set it), let&#8217;s think about this. Five bits gives us only 32 characters total to work with. We <em>need<\/em> the 26 Latin letters for English. There&#8217;s no way around that unless we do some sort of shifting. That leaves us only six more characters to work with. One of those characters will have to be a space. Another will have to mark line breaks. That leaves only four characters. Four! We don&#8217;t even have enough room for the ten digits!<\/p>\n<p>Ah, but that&#8217;s where you&#8217;re wrong. Let&#8217;s see how the above example code would look after it&#8217;s been prepared to be packed for storage. I&#8217;ll use semicolons here to denote the line break characters.<\/p>\n<p><code>FUNCTION EXAMPLE;LET INT $FOO BE BF;IF $FOO NOTBE BF THEN;$FOO BE CA PLUS BJG;ENDIF;ENDFUNCTION<\/code><\/p>\n<p>See what I did there? I encoded the digits using letters. 0 becomes A, 1 becomes B, 2 becomes C, and so on. And by using one of the four leftover characters as a dollar sign to mark variables, I made it impossible for variables to be mixed up with numbers or keywords, so this actually works. Furthermore, operators and mathematical symbols were converted to letter-based keywords, eliminating the need for punctuation. Since the script always follows the alternating pattern keyword->number->keyword->number this also works.<\/p>\n<p>It&#8217;s not without its problems though.<\/p>\n<p>Take the following, for example.<\/p>\n<p><code>$foo = ((2 + 2) * (5 + 3))<\/code><\/p>\n<p>See the problem? If you just converted the parentheses to keywords you&#8217;d have a problem. It wouldn&#8217;t follow the keyword->number->keyword->number pattern. The first opening parenthesis follows directly after the equal sign operator, and is then followed by a second opening parenthesis. That&#8217;s three keywords in a row. The parser would need some what to tell the opening parenthesis keyword from a number.<\/p>\n<p>But there are solutions to even this. If the keywords for parentheses were something like POPEN and PCLOSE you could get away with it because the parser couldn&#8217;t mistake them for numbers. They both start with the letter P and the highest digit 9 is encoded as J, so there&#8217;s no way it could be a valid number.<\/p>\n<p>Similarly, depending on how you want to use functions in the language, you&#8217;d probably want to take one of the three remaining character values to mark them with some sort of prefix, the way variables are denoted. This would practically be a <em>requirement<\/em> if you wanted functions in the scripting language that take parameters and return values. That leaves you with just two characters left.<\/p>\n<p>Another problem would be variable name collisions. $foo1 and $foob would both parse to $FOOB. Granted, if you&#8217;re requiring variables always be defined (such as with my verbose &#8220;let&#8221; keyword in the original example code), then the parser would catch these when packing for storage and notify the coder that their code has an error because $FOOB is already defined.<\/p>\n<p>You&#8217;d still have to do some sort of shifting if you wanted any kind of strings, though. Otherwise <code>string $bar = \"Hello, I am 9 years old today!\"<\/code> would come out, at best, as <code>STRING $BAR = \"HELLO I AM J YEARS OLD TODAY\"<\/code>. Notice I didn&#8217;t even try to encode the punctuation. For strings to be acceptable in the language, one of the two remaining character values would have to mark the beginning of a string, and then every pair of values after that would be parsed together as a ten bit value, enough to store all 128 ASCII characters and then some. The characters would be decoded like this until you hit some ten bit end-of-string character.<\/p>\n<p>So there you have it. Again, there&#8217;s really no reason to do <em>any<\/em> of this, other than because it can be done. But it was an interesting problem to solve, anyway.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last night in bed, as I was thinking about things that still need to be done for my next game before I can really start diving into it, I began thinking about the scripting engine. Another Star just hard-coded all scripting in C#, but, for one, there&#8217;s no way I&#8217;m scripting scenes in C++, and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22],"tags":[],"class_list":["post-882","post","type-post","status-publish","format-standard","hentry","category-programming"],"_links":{"self":[{"href":"https:\/\/www.visionriders.com\/blog\/wp-json\/wp\/v2\/posts\/882","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.visionriders.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.visionriders.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.visionriders.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.visionriders.com\/blog\/wp-json\/wp\/v2\/comments?post=882"}],"version-history":[{"count":8,"href":"https:\/\/www.visionriders.com\/blog\/wp-json\/wp\/v2\/posts\/882\/revisions"}],"predecessor-version":[{"id":890,"href":"https:\/\/www.visionriders.com\/blog\/wp-json\/wp\/v2\/posts\/882\/revisions\/890"}],"wp:attachment":[{"href":"https:\/\/www.visionriders.com\/blog\/wp-json\/wp\/v2\/media?parent=882"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.visionriders.com\/blog\/wp-json\/wp\/v2\/categories?post=882"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.visionriders.com\/blog\/wp-json\/wp\/v2\/tags?post=882"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}