Honk

A barebones programming language of a college final.
It can also honk.


                %% helloHonk.txt
                Program helloHonk;

                main() {
                  print("Hello Honk!");
                }
              

                > python3 honk.py helloHonk.txt
                Hello Honk!
              

                %% helloHonk.honk
                Untitled helloHonk game HONK

                Press y to honk
                OPEN FANCY GATE
                  SHOW ON TV "Hello Honk!" HONK
                CLOSE FANCY GATE
              

                > python3 honk.py helloHonk.honk
                Hello Honk!
              

The heck is this?

On my second-to-last semester, I took a compilers class, & it was hands down the hardest thing I've ever endured throughout my entire time in college. It was fascinating to see what goes on behind them, but I can confirm to you that it was very painful.

The class involved us making a project: a psuedo-compiler with specific requirements (you'll soon see how it has a bit of weirdness to it). And after all the turmoil and sleepless nights, Honk came to be.

Honk is essentially a barebones programming language developed by myself that can achieve basic tasks & has a few peculiar traits. It also can be pretty obnoxious and dumb to write, trust me.

What can it do?

For a barebones language, quite a few things. Its structure is comparable to something like C++, but with a few tricks up its sleeve:

  • Allow local and global variables
  • Variables can be atomic, arrays, or matrixes, & they can be of type integer, float, char, or boolean
  • Allow function declaration and calling, as well as recursion
  • Functions can return value of any of the mentioned types or be of type void
  • Allow assignments, arithmetic operations, & comparison expressions
  • Built-in read/write functions
  • Conditionals and loops
  • Special matrix operations
  • Special batch processes
  • Two different syntaxes: a normal one and a stupid vastly superior one

How do I run it?

The only requirements to using Honk is to run it through Python 3.6+ and have numpy installed. Once you have those, clone the repo and prepare to honk.

When you have a file ready to run through the compiler, run it through the command line:


                python3 honk.py <your file>
              

How do I write in Honk?

Let's get this out of the way first. Honk comes with two syntaxes: a regular syntax and a goose syntax. By default, running the command will run the compiler through the regular syntax. But if the input file is a .honk file, then it will use the goose syntax instead. You've been warned.

Keep this in mind when glancing at the references below.

General structure

To write a file in Honk, it will have to follow this general structure:


                Program <program_name>;
                [<global variable declarations>]
                [<function declarations>]

                %% Comments
                main() {
                  <statements>
                }
              

                Untitled <program_name> game HONK
                [<global variable declarations>]
                [<function declarations>]

                %% Comments
                Press y to honk
                OPEN FANCY GATE
                  <statements>
                CLOSE FANCY GATE
              

At the start of each program, you must declare the name of the program with Program <program_name>Untitled <program_name> game. Following that, you can optionally declare global variables & then after, functions declarations. A main function must be declared at the end with main()Press y to honk.

Note: Most statements are required to be terminated with ;HONK. Comments can be declared using %% at the start of your comment.

Variables

For both global and local variable declarations (the latter will be explained in a bit), they must be written in the following format:


                var
                  int a, b[2], c[7][4];
                  float f;
                  char ch;
                  bool bb, b[10][10];
              

                pond
                  WHOLE GOOSE a MOAR b OPEN BOX 2 CLOSE BOX 2 MOAR c OPEN BOX 7 CLOSE BOX OPEN BOX 4 CLOSE BOX HONK
                  PART GOOSE f HONK
                  LETTER GOOSE ch HONK
                  DUCK OR GOOSE bb OPEN BOX 10 CLOSE BOX OPEN BOX 10 CLOSE BOX HONK
              

Variables can be declared in two scopes: global (can be accessed in any context) or local (can only be accessed in a function's context). Global variables must be declared at the start of the program, while local variables are declared before a function's statements (before the {...}OPEN FANCY GATE ... CLOSE FANCY GATE). In both cases, variable declaration starts with varpond.

Variables can be of 4 types:

  • integer numbers (intWHOLE GOOSE)
  • floating type numbers (floatPART GOOSE)
  • characters (charLETTER GOOSE)
  • booleans (boolDUCK OR GOOSE)

Variables can also be either an atomic value, an array of values, or a matrix of values. Arrays and matrixes must define their dimensions in their declaration, using the appropriate notation: [<dimension>]OPEN BOX <dimension> CLOSE BOX

Note: You can define multiple variables of the same type in the same line using ,MOAR.

Functions

Functions can be called from any context (including itself for recursive operations), & they follow this format:


                function <type> <name>([<parameters>])
                [<local variable declarations>]
                {
                  <statements>
                }
              

                task <type> <name> HONK [<parameters>] HONK
                <local variable declarations>
                OPEN FANCY GATE
                  <statements>
                CLOSE FANCY GATE
              

Functions can be of any of the mentioned types above (and also any dimension, so it can return a matrix, for example); these functions must return a value. On the contrary, you can also make a function of type voidmy soul, & these must not return anything.

Functions can also have an optional number of <parameters>, each of which can be defined in the specified area and separated with ,MOAR.

Statements

Functions, of course, have statements within them. And Honk has the following statements you can use:

Assignment

                <var> = <expression>;
              

                <var> AM <expression> HONK
              
Void function call

                func(<params>);
              

                HOOONK func OPEN GATE <params> CLOSE GATE HONK
              
User input

                read(<var>, ...);
              

                HO- x -ONK HONK
              
Print

                print(<var>, ...);
              

                SHOW ON TV <var> HONK
              
Conditional

                if (expression) then { <statements> } [else { <statements> }]
              

                HONK? expression HONK! OPEN FANCY GATE <statements> CLOSE FANCY GATE [BONK OPEN FANCY GATE <statements> CLOSE FANCY GATE]
              
Return

                return(<var>);
              

                GOT BELL <var> HONK
              
While loop

                while (expression) do { <statements> }
              

                HONK HONK expression HOONK OPEN FANCY GATE <statements> CLOSE FANCY GATE
              
From loop

                from (var = <x> to <y>) do { <statements> }
              

                inhales var AM <x> HOOOONK <y>) HOOONK OPEN FANCY GATE <statements> CLOSE FANCY GATE
              
Break

                break;
              

                peace was never an option HONK
              

Expressions

An expression is basically a result from something. This can be simply a variable or a function call, but it can also be the result of the following operations:

Arithmetic

                %% Addition
                expr1 + expr2

                %% Substraction
                expr1 - expr2

                %% Multiplication
                expr1 * expr2

                %% Division
                expr1 / expr2

                %% Modulo
                expr1 % expr2
              

                %% Addition
                expr1 MORE GOOSE expr2

                %% Substraction
                expr1 LESS GOOSE expr2

                %% Multiplication
                expr1 GOOSETIPLY expr2

                %% Division
                expr1 GOOSIVIDE expr2

                %% Modulo
                expr1 LEFTOVERS expr2
              
Comparison

                %% Equal to
                expr1 == expr2

                %% Not equal to
                expr1 != expr2

                %% Less than
                expr1 < expr2

                %% Less than or equal to
                expr1 <= expr2

                %% More than
                expr1 > expr2

                %% More than or equal to
                expr1 >= expr2
              

                %% Equal to
                expr1 AM GOOSE? expr2

                %% Not equal to
                expr1 NOT GOOSE?! expr2

                %% Less than
                expr1 INFERIOR expr2

                %% Less than or equal to
                expr1 INFERIOR maybe expr2

                %% More than
                expr1 SUPERIOR expr2

                %% More than or equal to
                expr1 SUPERIOR maybe expr2
              
Logic

                %% AND
                expr1 & expr2

                %% OR
                expr1 | expr2
              

                %% AND
                expr1 TOGETHER FOREVER expr2

                %% OR
                expr1 POLE expr2
              
Matrix operations

                %% Determinant of a matrix
                expr$

                %% Transpose matrix
                expr!

                %% Inverse of a matrix
                expr?

                %% Dot product of a matrix
                expr1 . expr2
              

                %% Determinant of a matrix
                expr GOOSECOIN

                %% Transpose matrix
                expr SURPRISE

                %% Inverse of a matrix
                expr wh

                %% Dot product of a matrix
                expr1 doot expr2
              

Note: Matrix operations are a special set of operations that only work with matrixes. Bare in mind the restrictions when using them:

  • Determinant: Must be a square matrix
  • Transpose: The result of this operation will "flip" its dimensions
  • Inverse: Must be a square matrix
  • Dot product: Both matrixes must be compatible (the number of columns of the first matrix must equal the number of rows of the second matrix). The result will have different dimensions than the operands (same number of rows as the first matrix and same number of columns as the second matrix).

Batch operations

Another special characteristic of Honk are batch operations. They allow you to use regular operators with arrays and matrixes, allowing you to do "batch" statements without the need of a loop. The following functions/operations are batch-compatible:

  • Every operation that requires 2 operands, such as addition, multiplication, equality, logic gates, etc. (with the except of the dot product operator)
  • Assigning one array to another
  • Conditionals (they will act as AND gates, using every value in the array/matrix)
  • Print (print a whole collection without a loop)
  • User input (read input for a whole collection without a loop)

                Program matrix_stuff;
                int a[2][2], b[2][2], c[2][2];

                main() {
                  read(a);    %% Set a = [[1, 2], [3, 4]]
                  read(b);    %% Set b = [[2, 3], [4, 5]]

                  c = a + b   %% [[1, 2], [3, 4]] + [[2, 3], [4, 5]] = [[3, 5], [7, 9]]
                  print(c);   %% Print '[[3, 5], [7, 9]]'
                }
              

Note: For operations of 2 operands and assignments, the only restriction is that both matrixes in question have the same dimensions.

Now some questions...

Any caveats?

There are a few to mention here that should be taken into consideration:

  • Variables can live in only two scopes: global or local, which are defined at the start of the program or before a function's declaration, respectively. Variables in loops or conditionals do not give a higher scope, and variables can only be defined in those mentioned areas.
  • Every argument in a conditional are always evaluated. This usually isn't a problem, but in certain situations, it can cause issues. For example, short-circuiting doesn't exist with AND or OR expressions. So be mindful how you build your conditionals.
  • There will be bugs. It was a first attempt at creating a language and it was delivered only hours before the due date. Something's bound to happen.

Can I debug in this?

You can! During its development, I basically created my own debugging views to help me out, and I've made them available to use from the command line. You can see the available options with:


                python3 honk.py -h
              

Though in a nutshell these are the available arguments, all of which are optional:

  • -t / --tokens: Print all tokens found
  • -p / --parser: Enable debug info for parsing
  • -v / --vm: Enable debug info for virtual machine execution

Why call it a psuedo-compiler?

So the thing is that it does not directly translate the written code into machine code, rather it runs it through a virtual machine in Python. This virtual machine has restrictions and limitations to emulate the code being run through machine code, such as memory restrictions and usage of quads.

So you could say it is trying to act like a compiler, but it only emulates the behavior.

Why make the honk syntax, and who hurt you?

It was a challenge I gave and imposed on myself. And it was a pain, yes.

I was actually somewhat interested in joke languages, like LOLCODE and Whitespace. And I thought, after getting this tweet & that I will likely never do another one of these again:

Screw it, why the heck not?

I will warn you though: This is a very rushed and haphazardly put-together syntax. I literally designed the syntax a week before the deadline and implemented it 24 hours prior to delivery. And with a bunch of projects at the time, it isn't the best implementation by a long shot.

But I achieved out what I wanted to do, create a stupid language.

Did you pass the class?

BOY, I ACED IT. After the delivery of the project, it was required to spend like half an hour getting interogated by the professor about the language, and I'm pretty sure I got through that pretty well and got a laugh out of her when she found out the stupidity I had smeared onto the language with the goose syntax.

I popped off that day. I didn't know it was possible to pop off over code.

Are you gonna keep working on it?

No. Listen I did actually learn a lot from that class, and it gives me a newfound appreciation for the internals of a programming language and its compiler.

BUT HOO, WAS IT PAINFUL. The reason I'm making this write-up is because I told myself I would, & I know I worked way too hard to get this done throughout that barrage of projects I had that semester. I don't think I'd be interested in maintaining this whatsoever.

Just maybe it'll be of use to other people (or maybe as a funny joke, which honestly is a goal I had for this), but for now, Honk will be here for the sake of nostaligia or archival reasoning.

I wanna learn more about it!

Okay, first I'm surprised, but if you really wanna dive deep into it, you can clone the repo and check the source code out. I did my best to comment and explain as much as possible in the code. And here's the 60+ page document that I used to deliver it with. Fair warning though: while it has a lot of insightful information, I quite literally did almost all of it on the last day, so chances are it's got the occasional error.

Honestly, I'm genuinely curious as to why you wanna check it. Chances are that you bumped into the repo by luck, or you're a college friend of mine who's also suffering that class right now.

And if you're the latter, I send my condolences and the best of luck to ya.
also you can totally check the code out if you're stuck. Trust me I know it's difficult.