HASM and its sister project, SASM, is an esoteric language designed for any system. HASM takes its name and many features from assembly-style languages. Minimal syntactic sugar, combined with a simple instruction set, makes the simplest programs in HASM a challenge.
The HASM interpreter is written in C++ for all platforms. Development of HASM started in January 2020, in Python. The original (partly functional) project can be found on my Gists.
By default, HASM is built with g++ on all platforms.
In the base directory, there are compilation scripts for Windows and Linux systems.
Running the script for your platform will create the hasm
executable in the bin
directory.
For Linux systems, the compilation script will need to be made executable using chmod
.
Example build and execution processes for both systems are shown below.
cd hasm-cpp
chmod +x ./compile.sh
./compile.sh
cd ./bin
./hasm
cd hasm-cpp
compile
cd bin
hasm
As of version 1.3 (8/27/2020), running hasm
in the bin
directory will result in the following output.
[HASM]:
This field accepts any valid instruction (see Syntax), as well as the special commands place
and peek
.
Peek
is only active when the silent
flag is set, using the argument -s
.
Other command line arguments can be found in the Arguments section.
If the silent flag is not set, the status of the HASM memory space is printed after every command or instruction.
By default, you can exit the HASM interpreter by typing quit
or q
at the prompt, or by pressing ^C
.
Argument | Effect | Exits? |
---|---|---|
-c | Sets the character flag | n |
-d | Treats the following -e as devices |
n |
-e | Executes the specified file at startup | n |
-f | Sets the flag shift flag (use with -e) | n |
-h | Displays a help message | Y |
-l | Write commands to the specified file | n |
-s | Sets the silent flag | n |
-v | Displays a version message | Y |
In character mode, the contents of the HASM memory space is shown as character. The character flag can be used in combination with the silent flag. Character mode is designed for showing string of text in the memory. The character flag allows programs involving "strings" to be used.
With version 1.2 (7/5/20), the HASM interpreter now has the ability to execute files at startup.
To execute a file, start the interpreter with the -e
flag.
Specify the path of the file to be read after the -e
flag.
The contents of the file will be treated the same as many interpreter commands.
Comments can be specified using the ';' symbol, or can be left in the file unaltered.
However, using the ';' symbol will lead to the interpreter skipping the line, saving some performance.
Multiple execute flags can be chained to read multiple files.
In silent mode, the [HASM]:
message is not shown.
Additionally, the contents of the HASM memory space is hidden.
The contents of the memory space can be accessed using the peek
command.
Silent mode is designed for minimalist users, or for users who are presenting their development.
As of version 1.1, there is no way to toggle the silent flag within the interpreter.
Alias: m
Usage: mov SOURCE DESTINATION
Sets the memory at the address DESTINATION to the contents of the memory at the address SOURCE. Additionally, zeros out the memory at the address SOURCE.
Example: mov 5 6 # Move the memory at 5 to the memory at 6
Alias: ps
Usage: psh SOURCE
Decrements the stack pointer to move to the new address.
If the stack pointer is within bounds (greater than 0), the contents of the memory at SOURCE is placed at the stack pointer.
If the stack pointer is out of bounds, the stack pointer is reset to the location before the command was sent.
Additionally, the mem_out
flag is set.
Example: psh 3 # Pushes the memory at 3 onto the stack
Alias: pp
Usage: pop DESTINATION
Sets the contents of the memory at DESTINATION to the value at the stack pointer. Additionally resets the value at the stack pointer to be 0. If the stack pointer is within bounds (greater than 16), the stack pointer is incremented. Otherwise, the stack pointer is left untouched.
Example: pop 8 # Pops the value at the stack pointer to the memory at the address 8
Alias: a
Usage: add SOURCE DESTINATION
Adds the contents of the memory at the address SOURCE to the contents of the memory at the address DESTINATION.
If the memory at the address DESTINATION is less than 0, the neg
flag is set.
Example: add 9 5 # Adds the value at the address 9 to the value at the address 5
Alias: s
Usage: sub SOURCE DESTINATION
Subtracts the contents of the memory at the address SOURCE from the contents of the memory at the address DESTINATION.
If the memory at the address DESTINATION is less than 0, the neg
flag is set.
Example: sub 2 5 # Subtracts the value at the address 2 from the value at the address 5
Alias: i
Usage: inc DESTINATION
Increments the contents of the memory at the address DESTINATION by one.
If the memory at the address DESTINATION is less than 0, the neg
flag is set.
Example: inc 1 # Increments the value at the address 1 by one
Alias: d
Usage: dec DESTINATION
Decrements the contents of the memory at the address DESTINATION by one.
If the memory at the address DESTINATION is less than 0, the neg
flag is set.
Example: dec 1 # Decrements the value at the address 1 by one
Alias: p
Usage: place VALUE DESTINATION
Places the integer representation of the VALUE parameter into the memory at the address DESTINATION. This is a interpreter only command, and is not part of the HASM instruction set.
Example: place 65 1 # Places the value 65 at the address 1
Alias: pe
Prints the contents of the memory and the contents of the stack.
Peek
only works in silent mode.
In "normal" mode, the contents of the memory and the stack would be printed anyways, so no operations occur.
Example: peek # Prints the contents of the memory and stack
Alias: q
Exits the HASM interpreter.
Example quit # Exits the interpreter
All flags and registers are stored in the main memory area [0 - 31]. The flags and registers can be read and written to with no protection. The table below contains information about each flag.
Address | Flag | Usage | Boolean? |
---|---|---|---|
0 | jmp |
Address for the next jump operation | n |
1 | greater |
If the previous greater-than operation succeeded | Y |
2 | less |
If the previous less-than operation succeeded | Y |
3 | neg |
If the last math operation resulted in a negative number | Y |
4 | zero |
If the last zero comparison operation resulted in true | Y |
5 | none |
If the last move operation placed a zero at a location where there was previously a zero | Y |
6 | out |
If the stack was full when a psh operation was attempted |
Y |
7 | used |
If the jmp address was modified by a move operation |
Y |
As of June 2020, HASM is closed to outside contributions. However, help is always appreciated, especially on the following tasks.
inc
Increment the value of a register by 1dec
Decrement the value of a register by 1
- Possible C port?
Scanning and executing files on startup (command line argument)
As of right now there is no way for HASM to communicate with external processes. The long term vision of HASM is to implement the instructions on a physical device. This opens up the possibility for other devices to write to HASM's memory space. However as HASM is only in software, there is no way to do this.
My ideal solution would be an external device system, accompanied with a command such as
dev
.The
dev
command would open up a device sub-menu, which has a driver (written in HASM) that writes to the memory.These devices should be able to update on every instruction / cycle, which can be emulated with a
-d
flag.If anyone has ideas as to how I could implement this contact me with any of the methods listed under Contact.
Update (8/27/2020): I have added the -d
flag, which allows all following execute flags to be executed on every command.
Within the coming updates there will be a new argument for handling the behavior of commands in the flag memory space. When a command is executed and if the supplied address(es) are within the flag memory, the command will operate differently. The range for the flag memory space can be found in Flags and Registers. When the argument is not supplied, the command behaves like it would regardless of if it is within the flag memory space.
From a personal standpoint, HASM has room for improvement in terms of being compliant with the C++ standards. Performance does not seem to be an issue (for example, low process time on all systems). However, this does not mean there is no room for improvement. Again, contact me with any of the methods listed under Contact.
- StackOverflow for the
tokenize
function
Maintained by Hayden977.
Twitter: @Hayden977_
Discord: Hayden977#9614