w: Initial commit

This commit is contained in:
Louis Burke 2023-09-02 10:01:24 -04:00
commit e52878c5e2
4 changed files with 246 additions and 0 deletions

5
README.md Normal file
View file

@ -0,0 +1,5 @@
# ASCII Rendered, Compiled Target Invocation Code
Like the JVM, but the "binaries" consist of printable ASCII characters and the
result can be more easily precompiled for native execution.

133
doc/documentation.md Normal file
View file

@ -0,0 +1,133 @@
# ASCII Rendered, Compiled Target Invocation Code
Like the JVM, but the "binaries" consist of printable ASCII characters and the
result can be more easily precompiled for native execution.
## Opcodes
```{=todo}
Notate that immediates can be: …###, …###.###, …$name, or …v (for abcinxyz)
for most operations that take immediates.
```
### Summary
| -0 | -1 | -2 | -3 | -4 | -5 | -6 | -7
---:|:------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:
000-|`0 BNEZ`|`1 LDAB`|`2 LDAS`|`3 LDAI`|`4 LDAW`|`5 STAB`|`6 STAS`|`7 STAI`
001-|`8 STAW`|`9 CASS`|`A PUTA`|`B PUTB`|`C PUTC`|`D MCLR`|`E FTOI`|`F FREE`
010-|`G LDOI`|`H LDOS`|`I PUTI`|`J MOFF`|`K MCPY`|`L ROLL`|`M MNEW`|`N PUTN`
011-|`O ITOC`|`P PICK`|`Q LDOW`|`R MALL`|`S ITOS`|`T ????`|`U CMPU`|`V B_OR`
100-|`W ITOW`|`X PUTX`|`Y PUTY`|`Z PUTZ`|`a GETA`|`b GETB`|`c GETC`|`d MSET`
101-|`e SROT`|`f FMOD`|`g FINV`|`h OVER`|`i GETI`|`j FNEG`|`k SPOP`|`l BITC`
110-|`m FSUB`|`n GETN`|`o LDOB`|`p FMUL`|`q FDIV`|`r FREM`|`s FADD`|`t SWAP`
111-|`u USHR`|`v FABS`|`w SDUP`|`x GETX`|`y GETY`|`z GETZ`|`_ INEG`|`. ITOF`
200-|`+ IADD`|`- ISUB`|`* IMUL`|`/ IDIV`|`% IMOD`|`\ IREM`|`| IABS`|`$ VALU`
201-|`@ CALL`|`< BLTZ`|`{ BLEZ`|`= BEQZ`|`} BGEZ`|`> BGTZ`|`, JUMP`|`; RTRN`
210-|`& BAND`|`^ BXOR`|`! BNOT`|`[ BSHL`|`] BSHR`|`? CMPI`|`~ CMPF`|`: LABL`
211-|`( DPTH`|`) PACK`|`' IMP1`|`" IMP2`|`\` BKPT`|`␣ NOP`|`# COMM`|`¶ BEAT`
[Operations by code][ops-by-code]
In this table x, y, and z are integers; a, b, and c are floating point numbers;
p and q are memory pointers; and f is a function pointer. Additionally
→ indicates a basic operation, while ⇒ indicates an operation using an immediate
value, and ↔ indicates a meta operation.
Code | Stack | Description
-----:|:-------------------:|:--------------------------------------------------
0 BNEZ| … x ⇒ … | branch to immediate if x not zero
1 LDAB| … p → … x | load byte x from p
2 LDAS| … p → … x | load short x from p
3 LDAI| … p → … x | load int x from p
4 LDAW| … p → … x | load word x from p
5 STAB| … p x → … | store byte x to p
6 STAS| … p x → … | store short x to p
7 STAI| … p x → … | store int x to p
8 STAW| … p x → … | store word x to p
9 CASS| … p x y → … z | compare and swap x and y at p, return success
A PUTA| … x → … | store x in rA
B PUTB| … x → … | store x in rB
C PUTC| … x → … | store x in rC
D MCLR| … p x → … | memclear x bytes from p
E FTOI| … a → … x | round a to integer and store in x
F FREE| … p → … | free memory at p
G LDOI| … p ⇒ … x | load int at p plus immediate offset in x
H LDOS| … p ⇒ … x | load short at p plus immediate offset in x
I PUTI| … x → … | store x in rI
J MOFF| … p x → … q | set q to memory pointer p shifted by x bytes
K MCPY| … p q x → … | copy x bytes of memory from p to q
L ROLL| … x y ‥ z ⇒ … y ‥ z x | roll stack by immediate places
M MNEW| … ⇒ … p | allocate memory for immediate bytes at p
N PUTN| … x → … | store x in rN
O ITOC| … x → … x | truncate x to 8 bits, then sign extend
P PICK| … x ‥ z ⇒ … x ‥ z x | pick stack element at immediate place
Q LDOW| … p ⇒ … x | load word at p plus immediate offset in x
R MALL| … x → … p | allocate memory for x bytes at p
S ITOS| … x → … x | truncate x to 16 bits, then sign extend
T ????| | reserved for future instruction
U CMPU| … x y → … z | compare x to y unsigned and set z such that x o y is z o 0
V B_OR| … x y → … z | bitwise OR x and y and store in z
W ITOW| … x → … x | truncate x to 32 bits, then sign extend
X PUTX| … x → … | store x in rX
Y PUTY| … x → … | store x in rY
Z PUTZ| … x → … | store x in rZ
a GETA| … → … x | load x from rA
b GETB| … → … x | load x from rB
c GETC| … → … x | load x from rC
d MSET| … p x ⇒ … | set x bytes of memory to immediate value at p
e SROT| … x y z → … y z x | rotate stack
f FMOD| … a b → … c | set c to the modulo of a by b
g FINV| … f → f … | invoke f, saving return address on stack
h OVER| … x y → … x y x | stack over
i GETI| … → … x | load x from rI
j FNEG| … a → … a | negate a
k SPOP| … x → … | stack pop
l BITC| … x y → … z | bit clear y from x to z (z = x and not y)
m FSUB| … a b → … c | set c to the difference between a and b (a - b)
n GETN| … → … x | load x from rN
o LDOB| … p ⇒ … x | load byte at p plus immediate offset in x
p FMUL| … a b → … c | set c to the product of a and b
q FDIV| … a b → … c | set c to the quotient of a by b
r FREM| … a b → … c | set c to the remainder of a by b
s FADD| … a b → … c | set c to the sum of a and b
t SWAP| … x y → … y x | stack swap
u USHR| … x ⇒ … x | logical shift x by immediate bits right
v FABS| … a → … a | take the absolute value of a
w SDUP| … x → … x x | stack duplicate
x GETX| … → … x | load x from rX
y GETY| … → … x | load x from rY
z GETZ| … → … x | load x from rZ
_ INEG| … x → … x | negate x
. ITOF| … x → … a | convert x to a floating point number
\+ IADD|… x y → … z | set z to the sum of x and y
\- ISUB|… x y → … z | set z to the difference between x and y (x - y)
\* IMUL|… x y → … z | set z to the product of x and y
/ IDIV| … x y → … z | set z to the quotient of x by y
% IMOD| … x y → … z | set z to the modulo of x by y
\ IREM| … x y → … z | set z to the remainder of x by y
\| IABS|… x → … x | take the absolute value of x
$ VALU| … ↔ … * | load constant value
@ CALL| … ↔ … | call immediate name
< BLTZ| x | branch to immediate if x less than zero
{ BLEZ| … x ⇒ … | branch to immediate if x is less than or equal to zero
\= BEQZ|… x ⇒ … | branch to immediate if x is zero
} BGEZ| … x ⇒ … | branch to immediate if x is greater or equal to zero
\> BGTZ|… x ⇒ … | branch to immediate if x is greater than zero
, JUMP| … ⇒ … | jump to immediate without pushing return address
; RETN| … f ⇒ … | return from subroutine (jump but for stack)
& BAND| … x y → … z | set z to the bitwise and of x and y
^ BXOR| … x y → … z | set z to the bitwise xor of x and y
! BNOT| … x → y | set y to the bitwise not of x
[ BSHL| … x ⇒ … x | left shift x by immediate bits
] BSHR| … x ⇒ … x | arithmetic right shift x by immediate bits
? CMPI| … x y → … z | compare x to y and set z such that x o y is z o 0
~ CMPF| … a b ⇒ … c | compare a to b and set c such that a o b is z o c within an immediate error
\: LABL|… f ↔ … | label code location
( DPTH| … → … x | set x to depth of stack (before x)
) PACK| … p x → … | pack x elements of stack (before p) into array p
' IMP1| | implementation defined reserved operation 1 (no immediate)
" IMP2| | implementation defined reserved operation 2 (immediate)
\` BKPT| … ↔ … | trigger breakpoint, or exit if not debugging
␣ NOOP| … ↔ … | do nothing, maybe end identifier definition
¶ BEAT| … ↔ … | mark a beat for relative branching
[Operations in order][ops-in-order]

67
src/arctic.c Normal file
View file

@ -0,0 +1,67 @@
#include "arctic.h"
#include <string.h>
int arctic_max_expanded_size(int compressed_size) {
/* at most every 6th byte is free */
return (6 * compressed_size) / 5 + 1;
}
int arctic_max_compressed_size(int expanded_size) {
return (5 * expanded_size) / 6 + 1;
}
void arctic_expand(char *expanded, const char *compressed) {
// TODO
}
void arctic_compress(char *compressed, const char *expanded) {
// TODO
}
static const char *parse_immediate(const char *expanded, struct ArcticOperation *op) {
return expanded; // TODO
}
void arctic_normalize(struct ArcticOperation *ops, const char *expanded) {
const char *o = expanded;
struct ArcticOperation *op = ops;
*op = (struct ArcticOperation){ 0 };
while (*o) {
int opcode = *o++;
switch (*o) {
/* ops with an immediate */
case '0': case 'G': case 'H': case 'L': case 'M': case 'P':
case 'Q': case 'd': case 'o': case 'u': case '<': case '{':
case '=': case '}': case '>': case ',': case ';': case '[':
case ']': case '"':
o = parse_immediate(o, op);
/* ops without an immediate */
case '1': case '2': case '3': case '4': case '5': case '6':
case '7': case '8': case '9': case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F': case 'I': case 'J': case 'K':
case 'N': case 'O': case 'R': case 'S': case 'U': case 'V':
case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b':
case 'c': case 'e': case 'f': case 'g': case 'h': case 'i':
case 'j': case 'k': case 'l': case 'm': case 'n': case 'p':
case 'q': case 'r': case 's': case 't': case 'v': case 'w':
case 'x': case 'y': case 'z': case '_': case '.': case '+':
case '-': case '*': case '/': case '%': case '\\': case '|':
case '&': case '^': case '!': case '?': case '(': case ')':
op->opcode = opcode;
*++op = (struct ArcticOperation){ 0 };
break;
/* unusual ops */
case '$': case '@': case ':': case '`': case ' ': case '\n':
case '\'':
default: /* non-active characters */
break;
}
}
}

41
src/arctic.h Normal file
View file

@ -0,0 +1,41 @@
/* ARCTIC library header. To be used as a utility by interpreters and compilers.
* Author: Louis A. Burke
*/
#ifndef ARCTIC_H
#define ARCTIC_H
#include <stdint.h>
/* encoding/decoding */
int arctic_max_expanded_size(int compressed_size);
int arctic_max_compressed_size(int expanded_size);
void arctic_expand(char *expanded, const char *compressed);
void arctic_compress(char *compressed, const char *expanded);
/* normalization */
struct ArcticIdentifier {
const char *start; /* a pointer into the input, or null */
int length;
};
enum ArcticImmediateKind { ARCTIC_NAME, ARCTIC_INTEGER, ARCTIC_NUMBER };
struct ArcticImmediate {
enum ArcticImmediateKind kind;
union {
struct ArcticIdentifier name;
int64_t integer;
double number;
};
};
struct ArcticOperation {
struct ArcticIdentifier label;
struct ArcticImmediate immediate;
int opcode; /* won't be beat or nop or comm */
};
void arctic_normalize(struct ArcticOperation *ops, const char *expanded);
#endif /* ARCTIC_H */