Table of contents
- Instructions
- Literals
- Labels
- Constant expressions
- Variables
- Macros
- Includes
- Embeds
- Comments
- Examples
Instructions
All instructions in ANASM are 3 characters long. Their names are the same as specified in the AVM documentation, except they are lower case.
Some instructions take a parameter. That parameter is written right after the instruction, separated from the instruction by a space, like so
INST PARAMETER
Literals
Instruction parameters are all just numbers, but they are a bit abstracted in anasm. One type of parameters are literals. Literals can be decimal integers, hexadecimal integers, octal integers, binary data, floating point numbers or ascii characters.
Decimal
Decimal integers have no prefix, they are written like normal decimal integers
1024
5
256
Hexadecimal
Hexadecimal integers are prefixed with 0x or 0X, and the letters in them can be both lower or upper case
0xff
0xEDA
0X5AB4ED
Octal
octal integers are prefixed with 0o or 0O
0o7
0O452
Binary
Binary data is prefixed with 0b or 0B
0b110
0B11010
Floating point numbers
Floating point numbers, similar to decimal integers, are written normally, with no prefix, and the floating point is marked with a .
3.14
12.7
ASCII characters
ASCII character literals are surrounded by ' and can only be a single character. There are exceptions - the escape sequences, which are talked about later in the strings escape sequences section
'A'
'$'
Strings
String literals are special, because they cannot be passed as parameters to instructions. They can only be assigned to variables. Strings are surrounded by " quotes
"Hello, world!"
"How are you?"
Escape sequences
Strings also have escape sequences, which are used for putting special ascii characters that are not printable into the string, such as a newline or the carriage return. These escape sequences start with a \ and are two characters long (including the slash). This is a table of the escape sequences and the bytes they turn into
Escape sequence | Value |
---|---|
\0 | 0x00 |
\a | 0x07 |
\b | 0x08 |
\e | 0x1b |
\f | 0x0c |
\n | 0x0a |
\r | 0x0d |
\t | 0x09 |
\v | 0x0b |
\\ | 0x5c (\) |
\" | 0x22 (") |
\' | 0x27 (') |
Example of escape sequences in a string
"Hello, world!\n"
Labels
Another type of instruction parameters are labels. Labels mark a position in the program (an instruction address), so we can jump to that position easily, without having to manually calculate its address. When we create a label, we prefix it with a . and then type the name after it
.my_label
psh 5
This label holds the address of the psh instruction right below it. Example of using the label:
jmp my_label
Label names can only contain lower case or upper case ASCII letters, digits, _ and $
Entry point label
A special kind of label is the entry point label, which is defined with
.entry
This label marks the start of the program - where the program will begin executing.
Constant expressions
Constant expressions allow you to do calculations which will be evaluated at compile time. Instead of using a calculator to divide 8 by 2, you can use a constant expression to calculate it. The syntax is similar to lisp:
(OPERATOR PARAMS)
where OPERATOR is one of the available operators to use, and PARAM are its parameters. See the table of operations
Operation | Description |
---|---|
+ | Any amount of parameters, adds them together |
- | Any amount of parameters, subtracts them |
* | Any amount of parameters, multiplies them |
/ | Any amount of parameters, divides them |
% | Any amount of parameters, performs modulus on them |
^ | Any amount of parameters, performs power on them |
& | Any amount of parameters, performs bit and on them |
| | Any amount of parameters, performs bit or on them |
>> | Any amount of parameters, performs bit shifting to right on them |
<< | Any amount of parameters, performs bit shifting to left on them |
sizeof | One parameter, which can be either a type or a variable, and returns its size |
The true power of constant expressions comes with using them to calculate an offset of a variable, for example:
let NUMS byte = 5, 12
.entry
psh (+ NUMS 1)
r08
prt
This example would print 12.
Nested constant expressions are also allowed:
prt (+ (+ 5 5) 2)
However, constant expressions do not work with floating point numbers as you would expect. All simple literals are turned into words at compile time, and these constant expression operators operate on them as if they were integers, because they have no way of knowing what they were originally.
Variables
Being able to write data to memory is nice, but manually keeping track of all the addresses and stuff is painful. For automating this, ANASM has the let keyword, which is used to define variables that automatically calculate their address in memory.
The syntax of the keyword is
let NAME TYPE = DATA
where NAME is the name of the variable that we will use to reference it (variable names can only contain the same characters as label names), TYPE is the type (size) of a single element and DATA is a list of the data it holds. The available types are below
Keyword | Size (in bytes) |
---|---|
char | 1 |
byte | 1 |
i16 | 2 |
i32 | 4 |
i64 | 8 |
f64 | 8 |
The data list elements are separated with a , and can be anything of the literals (including strings). Example of a valid variable
let ABC char = 'a', 'b', 'c'
This variable will be 3 bytes in total, because it contains 3 data elements each of the size 1 byte (sz8)
Using the variables data addresses is the same as with labels.
psh @ABC
r08
prt
Macros
Macros are made to eliminate magic numbers. They are identifiers tied to a value, and when they are used somewhere, they are replaced by that value during compilation. The syntax of a macro definition is
mac NAME = DATA
where NAME is the name of the macro and DATA is the value it will be replaced with. Example:
mac FIVE_PLUS_TWO = (+ 5 2)
.entry
psh FIVE_PLUS_TWO
prt
Includes
To avoid long source files, anasm provides file including. Including simply copy-pastes the code of the included file into the source file. The syntax is
include PATH
where PATH is the path of the file to include. Example:
include "test.anasm"
Embeds
To eliminate the cost and annoyance of reading files at runtime, you can embed the file into the programs memory at compilation. The syntax is
emb NAME PATH
where NAME is the name of the variable with the file contents, and PATH is the path of the file to embed. Example:
emb MY_FILE "file.txt"
Identifiers created by the emb keyword are just like variables with element type char. The data is not ended by a 0 or by an EOF.
Comments
Comments are an important part of assembly, because without them you will probably forget how any of the code works. Comments start with a # and last until the end of the line
# Hello, i am a comment!
Examples
Probably the best way to learn is by seeing examples. Example ANASM programs are in the examples folder in the ANASM github repo.