aboutsummaryrefslogtreecommitdiff
path: root/pu2/pu2.c
diff options
context:
space:
mode:
authorGravatar moon <moon@coffin.ir> 2025-08-22 19:09:46 +0330
committerGravatar moon <moon@coffin.ir> 2025-08-22 19:09:46 +0330
commit1e7e5ee85963aee23b71fa59cd622a06f27e1a6e (patch)
tree87d527b9436b99c3498e615c3ce7350962a7ba8c /pu2/pu2.c
parentadded jmp, jnz and jz (diff)
if statements are now supported!
Diffstat (limited to 'pu2/pu2.c')
-rw-r--r--pu2/pu2.c273
1 files changed, 209 insertions, 64 deletions
diff --git a/pu2/pu2.c b/pu2/pu2.c
index 2916582..7640039 100644
--- a/pu2/pu2.c
+++ b/pu2/pu2.c
@@ -229,7 +229,7 @@ clean_slice_ref(slice_t *val) { free(val->ref); }
})
#define scanword() \
({ \
- slice_t VAR = { 0, I }; \
+ slice_t VAR = { 0, I }; \
while (isalnum(*I) || *I == '_') VAR.len++, I++; \
VAR; \
})
@@ -270,11 +270,11 @@ clean_slice_ref(slice_t *val) { free(val->ref); }
})
// #define emit(OP, VAL) (*Code++ = (OP), *Code++ = (VAL))
-#define store() (emit(opcode.acc, 1), emit(opcode.str, 0))
+#define store() (emit(opcode.acc, 1), op(str))
#define op(mode) emit(opcode.mode, 0)
-#define swap() emit(opcode.swp, 0)
+#define swap() op(swp)
#define imm(value) emit(opcode.imm, value)
-#define load() emit(opcode.lod, 0)
+#define load() op(lod)
#define imm_in_mem(__mem, __imm) (imm(__mem), emit(opcode.cb3, __imm))
#define mov_mem_mem(__mem1, __mem2) (imm(__mem1), emit(opcode.cb4, __mem2))
#define mem_in_a(__mem) emit(opcode.cb2, __mem)
@@ -283,13 +283,12 @@ clean_slice_ref(slice_t *val) { free(val->ref); }
mem_in_a(mem2_index); \
swap(); \
mem_in_a(mem_index); \
- emit(opcode.operation, 0); \
+ op(operation); \
swap(); \
imm(mem_index); \
store(); \
})
-char T;
string ERR;
string ERR_code;
int *Code;
@@ -305,28 +304,86 @@ __attribute__((always_inline)) emit(int op, int val) {
*Code++ = val;
}
+int ir2_depth = 0;
+
+#define space skip_space(&I)
+
bool has_jump_warned = false;
-_ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delegated_t forward_refs[ 1 << 10 ]) {
+bool has_useless_if_warned = false;
+
+string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delegated_t forward_refs[ 1 << 10 ]) {
+ char T;
string init_I = I;
ERR = "all good";
while (T = *I) {
- skip_space(&I);
+ if (isspace(T)) {
+ space;
+ continue;
+ }
+
+ string start_I = I;
- if (T == '/' && I[ 1 ] == '/') { // comment
+ if (T == '}') {
+ if (ir2_depth == 0) run_err(I, "unexpected closing bracket");
+ ir2_depth--;
+
+ return ++I;
+ }
+
+ else if (T == '/' && I[ 1 ] == '/') { // comment
I += 2;
while (*I != '\n' && *I != '\0') I++;
+ continue;
+ }
+
+ else if (T == '/' && I[1] == '*') { // multi-line comment
+ string old_I = I;
+ I+= 2;
+ while (*I != '*' || I[1] != '/') {
+ if (I[1] == '\0') {
+ run_err(old_I, "reached EOF whilst looking for closing comment delimeter");
+ }
+
+ I++;
+ }
+ I += 2;
+ continue;
}
// handle assignments!
- if (T == '@') {
+ else if (T == '@') {
I++;
+ if (!isdigit(*I)) { run_err(I, "expected a digit after @"); }
int mem_index = strtol(I, &I, 10);
- skip_space(&I);
+ space;
+
+ if(*I == '-' && I[1] == '-') { // decrement
+ I += 2;
+ space;
+ checkskip(';', "expected semicolon");
+ imm(1);
+ swap();
+ mem_in_a(mem_index);
+ op(sub);
+ store();
+ }
+
+ if(*I == '+' && I[1] == '+') { // increment
+ I += 2;
+ space;
+ checkskip(';', "expected semicolon");
+ imm(1);
+ swap();
+ mem_in_a(mem_index);
+ op(add);
+ store();
+ }
+
char extra_op = '=';
if (*I == '+' || *I == '-' || *I == '&' || *I == '!') extra_op = *I++;
checkskip('=', "expected assigment after memory blob (hint: only +-&! are supported)");
- skip_space(&I);
+ space;
if (mem_index == 7 && !has_jump_warned) {
has_jump_warned = true;
@@ -351,7 +408,7 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
} else if (extra_op == '!') {
// @1 != @2;
mem_in_a(mem2_index);
- emit(opcode.not, 0);
+ op(not);
swap();
imm(mem_index);
store();
@@ -365,7 +422,7 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
imm(imm);
swap();
mem_in_a(mem_index);
- emit(opcode.add, 0);
+ op(add);
swap();
imm(mem_index);
store();
@@ -373,45 +430,46 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
imm(imm);
swap();
mem_in_a(mem_index);
- emit(opcode.sub, 0);
+ op(sub);
store();
} else if (extra_op == '&') {
imm(imm);
swap();
mem_in_a(mem_index);
- emit(opcode.and, 0);
+ op(and);
store();
} else if (extra_op == '!') {
// @1 != 5;
imm(imm);
- emit(opcode.not, 0);
+ op(not);
swap();
imm(mem_index);
store();
}
}
- skip_space(&I);
+ space;
checkskip(';', "expected semicolon");
continue;
}
// register macros
- if (strncmp("macro", I, 5) == 0 && isspace(I[ 5 ])) {
+ else if (strncmp("macro", I, 5) == 0 && isspace(I[ 5 ])) {
I += 6;
- skip_space(&I);
+ space;
// parse macro stuff
if (!isalpha(*I) && *I != '_') {
run_err(I - 1, "expected letter or underscore at macro name");
}
+ string old_I = I;
slice_t name = scanword();
- skip_space(&I);
+ space;
checkskip('(', "expected open paren in macro defintion");
- skip_space(&I);
+ space;
string before = I;
int arg_count = strtol(I, &I, 10);
@@ -419,14 +477,14 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
run_err(I, "expected number (argument count) in macro definition parens");
}
- skip_space(&I);
+ space;
checkskip(
')',
"expected close paren in macro definition (hint: macro defintions only take an "
"argument count)");
- skip_space(&I);
+ space;
checkskip('{', "expected open curly bracket in macro body");
@@ -434,14 +492,17 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
int x;
for (x = 0; x < (1 << 9); x++) {
macro_t g = macros[ x ];
- if (g.data.key.ref == NULL) { goto DONE; }
+ if (g.data.key.ref == NULL) goto DONE;
+ if (g.data.key.len == name.len && strncmp(g.data.key.ref, name.ref, name.len) == 0) {
+ run_err(old_I, "redefinition of macro");
+ }
}
run_err(I - 1, "registered macro count exceeded 1<<9 (how?)");
DONE:;
- skip_space(&I); // might aswell skip whitespace for funsies.
+ space; // might aswell skip whitespace for funsies.
macro_t *g = &macros[ x ];
g->data.key = name;
g->data.value.ref = I;
@@ -465,7 +526,7 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
}
// emit exit calls
- if (strncmp("exit", I, 4) == 0) {
+ else if (strncmp("exit", I, 4) == 0) {
I += 4;
checkskip('(', "expected open paren on exit blob");
@@ -475,53 +536,52 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
run_err(I - 1, "invalid input to exit blob, expected number");
}
- skip_space(&I);
+ space;
checkskip(')', "expected open paren on exit blob");
- skip_space(&I);
+ space;
checkskip(';', "expected semicolon after call");
// actually emit stuff
if (old != I) emit(opcode.imm, value);
- emit(opcode.hlt, 0);
+ op(hlt);
continue;
}
// emit system
- if (strncmp("system", I, 6) == 0 && !isalnum(I[ 6 ])) {
+ else if (strncmp("system", I, 6) == 0 && !isalnum(I[ 6 ])) {
I += 6;
- skip_space(&I);
+ space;
checkskip('(', "expected open paren on system blob");
- skip_space(&I);
+ space;
checkskip(
')',
"expected closing paren on system blob (hint: system does not take any arguments)");
- skip_space(&I);
+ space;
checkskip(';', "expected semicolon after system blob");
imm_in_mem(0, 2);
- emit(opcode.hlt, 0);
+ op(hlt);
continue;
}
- if (strncmp("jump", I, 4) == 0 && !isalnum(I[4])) {
+ else if (strncmp("jump", I, 4) == 0 && !isalnum(I[4])) {
I += 4;
goto PARSE_JUMP_BLOB;
}
- if (strncmp("jmp", I, 3) == 0 && !isalnum(I[3])) {
+ else if (strncmp("jmp", I, 3) == 0 && !isalnum(I[3])) {
I += 3;
PARSE_JUMP_BLOB:
- skip_space(&I);
+ space;
checkskip('(', "expected open paren on jump blob");
- skip_space(&I);
+ space;
if(!isalpha(*I)) run_err(I, "expected a label name for jump blob argument");
- slice_t label = { 1, I };
- while (isalnum(*++I)) label.len++;
- skip_space(&I);
+ slice_t label = scanword();
+ space;
checkskip(')', "expected closing paren after label name in jump blob");
- skip_space(&I);
+ space;
checkskip(';', "excpected semicolon after jump blob");
// resolve right now if the label exists
@@ -557,31 +617,31 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
del->name = label;
del->init_I = init_I;
- FINISH_JMP:;
+ FINISH_JMP:
+ continue;
}
- if ((strncmp("jnz", I, 3) == 0 && !isalnum(I[3])) || (strncmp("jz", I, 2) == 0 && !isalnum(I[2]))) {
+ else if ((strncmp("jnz", I, 3) == 0 && !isalnum(I[3])) || (strncmp("jz", I, 2) == 0 && !isalnum(I[2]))) {
bool was_jnz = !!strncmp("jz", I, 2);
string name = was_jnz ? "jnz" : "jz";
I += was_jnz ? 3 : 2;
- skip_space(&I);
+ space;
checkskip('(', "expected open paren on %s blob", name);
- skip_space(&I);
+ space;
checkskip('@', "expected memory address format as first %s argument (example: `%s(@5, label_name);`)", name, name);
int target_mem = strtol(I, &I, 10);
- skip_space(&I);
+ space;
checkskip(',', "expected comma (second argument) in %s blob (example: `%s(@5, label_name);`)", name, name);
- skip_space(&I);
+ space;
if(!isalpha(*I)) run_err(I, "expected a label name for %s blob's second argument (example: `%s(@5, label_name);`)", name, name);
- slice_t label = { 1, I };
- while (isalnum(*++I)) label.len++;
- skip_space(&I);
+ slice_t label = scanword();
+ space;
checkskip(')', "expected closing paren after label name in %s blob (do i really need to explain this to you again?)", name);
- skip_space(&I);
+ space;
checkskip(';', "excpected semicolon after %s blob", name);
// resolve right now if the label exists
@@ -620,7 +680,7 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
WRITE_DEL_JNZ:
- // emit jnz
+ // emit j(n)z
mem_in_a(target_mem);
if (!was_jnz) op(not);
op(a2u);
@@ -633,13 +693,87 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
del->name = label;
del->init_I = init_I;
- FINISH_JNZ:;
+ FINISH_JNZ:
+ continue;
+ }
+
+ else if (strncmp("if", I, 2) == 0 && !isalnum(I[2])) {
+ // if statement
+ I += 2;
+ space; checkskip('(', "expected open paren for if statement"); space;
+
+ ir2_depth++;
+
+ if (isdigit(*I)) {
+ if (!has_useless_if_warned) {
+ has_useless_if_warned = true;
+ printf("warn: redundant if statement\n");
+ }
+
+ // redundant if statement: always true / always false
+ int value = strtol(I, &I, 10); space;
+ checkskip(')', "expected closing paren after if statement argument"); space;
+ checkskip('{', "expected opening bracket for if statement body"); space;
+
+ if (!value) {
+ // just skip over everything inside
+
+ int *Code_B = Code;
+ int *Data_B = Data;
+
+ // get new I location
+ string new_I = _ir2(I, macros, labels, forward_refs);
+ I = new_I;
+ // restore values
+ Code = Code_B;
+ Data = Data_B;
+
+ continue;
+ }
+
+ else {
+ // just... i mean, i guess run the code..?
+ string new_I = _ir2(I, macros, labels, forward_refs);
+ I = new_I;
+ continue;
+ }
+ }
+
+ bool was_negated = false;
+ if (*I == '!') {
+ was_negated = true;
+ I++; space;
+ }
+
+ checkskip('@', "expected memory address for if statement expression (hint: only simple if statements are supported)");
+ if (!isdigit(*I)) run_err(I, "expected memory index");
+ int mem_index = strtol(I, &I, 10); space;
+ checkskip(')', "expected closing paren after if statement argument"); space;
+ checkskip('{', "expected opening bracket for if statement body"); space;
+
+ mem_in_a(mem_index);
+ if (!was_negated) op(not);
+ op(a2u);
+ imm(0xDEAD10C4); // DEADLOCK - placeholder for the patchback
+ int* patchback = Code - 1;
+ swap();
+ imm(7);
+ op(str);
+
+ // handle the code stuff
+ string new_I = _ir2(I, macros, labels, forward_refs);
+ I = new_I;
+
+ *patchback = Code - m; // patch the jump instruction
+
+ continue;
}
// macro call, maybe?
- if (isalpha(*I)) {
+ else if (isalpha(*I)) {
+ string old_I = I;
slice_t name = scanword();
- skip_space(&I);
+ space;
if(*I == ':') {
I++;
@@ -647,12 +781,18 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
label_t *slot;
int j;
for (j = 0; j < 1 << 10; j++) {
- if (labels[j].name.ref != NULL) continue;
+ if (labels[j].name.ref != NULL) {
+ if (labels[j].name.len == name.len && strncmp(labels[j].name.ref, name.ref, name.len) == 0) {
+ run_err(old_I, "redefinition of label");
+ }
+ continue;
+ }
+
slot = &labels[j];
goto FOUND_SLOT;
}
- run_err(I - 1, "registered label count exceeded 1<<10 (how?)");
+ run_err(old_I, "registered label count exceeded 1<<10 (how?)");
FOUND_SLOT:
slot->name = name;
@@ -662,7 +802,7 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
}
checkskip('(', "expected open paren after alphanumeric word (assuming this is a blob)");
- skip_space(&I);
+ space;
slice_t arguments[ 1 << 7 ];
size_t arg_count = 0;
@@ -689,17 +829,17 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
}
}
- skip_space(&I);
+ space;
checkskip(']', "expected closing bracket in macro arguments");
- skip_space(&I);
+ space;
if (*I != ',' && *I != ')') {
run_err(I, "expected comma or closing paren in blob");
}
if (*I == ',') {
I++;
- skip_space(&I);
+ space;
}
arg_count++;
@@ -708,7 +848,7 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
fail_I = I;
checkskip(')', "expected closing paren after blob arguments");
- skip_space(&I);
+ space;
checkskip(';', "expected semicolon after blob");
// done reading blob! check it and parse macro :)
@@ -785,7 +925,12 @@ _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delega
continue;
}
+
+ // unknown
+ else run_err(I, "unknown token '%c' (%i)", T, T);
}
+
+ return I;
}
ir2(string I) {