aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pu2/code.i27
-rw-r--r--pu2/pu2.c405
2 files changed, 254 insertions, 158 deletions
diff --git a/pu2/code.i2 b/pu2/code.i2
index 22ab74f..b173469 100644
--- a/pu2/code.i2
+++ b/pu2/code.i2
@@ -1,5 +1,4 @@
-
/*
testing grounds for the ir2 assembler
@@ -23,10 +22,10 @@ macro putchar(1) {
system();
}
-@90 = 5;
+let count = 5;
-while (@90) {
- @90--;
+while (count) {
+ count--;
puts(["hello"], [5]);
putchar([10]);
diff --git a/pu2/pu2.c b/pu2/pu2.c
index c097873..61886c0 100644
--- a/pu2/pu2.c
+++ b/pu2/pu2.c
@@ -236,38 +236,58 @@ clean_slice_ref(slice_t *val) { free(val->ref); }
#define memslice_t slice_t __attribute__((cleanup(clean_slice_ref)))
#define readd() ((used == new.len) ? (new.ref = realloc(new.ref, new.len *= 2)) : 0)
#define scanvalue() \
- ({ /* value scanner! numbers, characters, strings. */ \
- int value; \
- if (isdigit(*I)) { \
- value = strtol(I, &I, 10); \
- } else if (*I == '\'') { \
- I++; \
- value = *I++; \
- checkskip('\'', "couldn't find closing quote on character"); \
- } else if (*I == '"') { \
- string str_start = ++I; \
- bool T = false; \
- size_t str_len = 0; \
- while (*I != '"' || T) { \
- if (*I == '\\') { \
- T = !T; \
- if (!T && I[ 1 ] == '"') str_len--; \
- } \
- str_len++; \
- I++; \
- } \
- I++; \
- str_len++; \
- int *dest_start = Data -= str_len; \
- int y; \
- for (y = 0; y < str_len - 1; y++) { dest_start[ y ] = str_start[ y ]; } \
- Data[ -1 ] = 0; \
- value = Data - m; \
- } else { \
- run_err(I, "expected value (number, character, string)"); \
- } \
- value; \
+ ({ /* value scanner! numbers, characters, strings, variable derefs. */ \
+ int value; \
+ if (isdigit(*I)) { \
+ value = strtol(I, &I, 10); \
+ } else if (*I == '\'') { \
+ I++; \
+ value = *I++; \
+ checkskip('\'', "couldn't find closing quote on character"); \
+ } else if (*I == '"') { \
+ string str_start = ++I; \
+ bool T = false; \
+ size_t str_len = 0; \
+ while (*I != '"' || T) { \
+ if (*I == '\\') { \
+ T = !T; \
+ if (!T && I[ 1 ] == '"') str_len--; \
+ } \
+ str_len++; \
+ I++; \
+ } \
+ I++; \
+ str_len++; \
+ int *dest_start = Data -= str_len; \
+ int y; \
+ for (y = 0; y < str_len - 1; y++) { dest_start[ y ] = str_start[ y ]; } \
+ Data[ -1 ] = 0; \
+ value = Data - m; \
+ } else if (*I == '&') { \
+ I++; \
+ string starting_I = I; \
+ slice_t name = scanword(); \
+ value = __ir2_get_var_loc(name, variables, starting_I, init_I); \
+ } else { \
+ run_err(I, "expected compile-time value (number, character, string, dereference)"); \
+ } \
+ value; \
})
+#define scanvar() \
+ ({ /* memory scanner! finds @10, var_name */ \
+ int value; \
+ if (*I == '@') { \
+ if (!isdigit(*++I)) run_err(I - 1, "expected memory index"); \
+ value = strtol(I, &I, 10); \
+ } else if (isalpha(*I) || *I == '_') { \
+ string starting_I = I; \
+ slice_t name = scanword(); \
+ value = __ir2_get_var_loc(name, variables, starting_I, init_I); \
+ } else run_err(I, "expected memory index or variable"); \
+ value; \
+ })
+#define varqual(F) ((F) == '@' || isalpha(F) || (F) == '_')
+#define litqual(F) (isdigit(F) || (F) == '\'' || (F) == '"' || (F) == '&')
// #define emit(OP, VAL) (*Code++ = (OP), *Code++ = (VAL))
#define store() (emit(opcode.acc, 1), op(str))
@@ -312,7 +332,21 @@ bool has_jump_warned = false;
bool has_useless_if_warned = false;
bool has_false_while_warned = false;
-string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delegated_t forward_refs[ 1 << 10 ]) {
+__ir2_get_var_loc(slice_t name, label_t variables[ 1 << 11 ], string error_I, string init_I) {
+ int j;
+ for (j = 0; j < 1 << 11; j++) {
+ label_t cur = variables[ j ];
+ if (cur.name.ref == NULL) break;
+ if (cur.name.len != name.len) continue;
+ if (strncmp(cur.name.ref, name.ref, name.len) == 0) {
+ return cur.location;
+ }
+ }
+
+ run_err(error_I, "unknown variable name \"%.*s\"", name.len, name.ref);
+}
+
+string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delegated_t forward_refs[ 1 << 10 ], label_t variables[ 1 << 11 ]) {
char T;
string init_I = I;
ERR = "all good";
@@ -332,13 +366,13 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
return ++I;
}
- else if (T == '/' && I[ 1 ] == '/') { // comment
+ if (T == '/' && I[ 1 ] == '/') { // comment
I += 2;
while (*I != '\n' && *I != '\0') I++;
continue;
}
- else if (T == '/' && I[1] == '*') { // multi-line comment
+ if (T == '/' && I[1] == '*') { // multi-line comment
string old_I = I;
I+= 2;
while (*I != '*' || I[1] != '/') {
@@ -352,118 +386,70 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
continue;
}
- // handle assignments!
- else if (T == '@') {
- I++;
- if (!isdigit(*I)) { run_err(I, "expected a digit after @"); }
- int mem_index = strtol(I, &I, 10);
- space;
-
- if(*I == '-' && I[1] == '-') { // decrement
- I += 2;
- space;
- checkskip(';', "expected semicolon");
- imm(1);
- swap();
- mem_in_a(mem_index);
- op(sub);
- swap();
- imm(mem_index);
- store();
+ // define variable
+ if (strncmp("let", I, 3) == 0 && isspace(I[3])) {
+ I += 3; space;
+ string backname_I = I;
+ slice_t name = scanword(); space;
+ int *m_index = --Data;
+ int start_index = m_index - m;
- continue;
- }
+ // comment out this flag to initialize values at runtime instead of compile-time
+ #define IR2_INIT_COMPILE_TIME
- if(*I == '+' && I[1] == '+') { // increment
- I += 2;
+ if (*I == ';') {
+ // no starter value, just initialize it to zero
+ I++;
+ #ifdef IR2_INIT_COMPILE_TIME
+ *m_index = 0;
+ #else
+ imm_in_mem(start_index, 0);
+ #endif
+ } else {
+ checkskip('=', "expected semicolon or assignment in variable declaration");
space;
- checkskip(';', "expected semicolon");
- imm(1);
- swap();
- mem_in_a(mem_index);
- op(add);
- swap();
- imm(mem_index);
- store();
-
- continue;
- }
- char extra_op = '=';
- if (*I == '+' || *I == '-' || *I == '&' || *I == '!') extra_op = *I++;
- checkskip('=', "expected assigment after memory blob (hint: only +-&! are supported)");
- space;
+ if (litqual(*I)) { // literal
+ #ifdef IR2_INIT_COMPILE_TIME
+ *m_index = scanvalue();
+ #else
+ imm_in_mem(start_index, scanvalue());
+ #endif
+ } else if (varqual(*I)) { // memory address
+ I++;
+ int mem_index = scanvar();
+ mov_mem_mem(start_index, mem_index);
+ } else {
+ run_err(I, "expected compile-time constant, variable or memory index");
+ }
- if (mem_index == 7 && !has_jump_warned) {
- has_jump_warned = true;
- printf("\nwarn: writing to memory index 7 is equivalent to a jump\n");
- printf(" if this behavior is intended, use the jump blob instead.\n\n");
+ space;
+ checkskip(';', "expected semicolon after variable value");
}
- if (*I == '@') {
- I++;
- if (!isdigit(*I)) { run_err(I, "expected a digit after @"); }
-
- int mem2_index = strtol(I, &I, 10);
+ int j;
+ for (j = 0; j < 1 << 11; j++) {
+ label_t cur = variables[ j ];
- if (extra_op == '=') {
- mov_mem_mem(mem_index, mem2_index);
- } else if (extra_op == '+') {
- perform_op(add);
- } else if (extra_op == '-') {
- perform_op(sub);
- } else if (extra_op == '&') {
- perform_op(and);
- } else if (extra_op == '!') {
- // @1 != @2; (@1 = !@2)
- mem_in_a(mem2_index);
- op(not);
- swap();
- imm(mem_index);
- store();
+ if (cur.name.ref == NULL) {
+ variables[ j ].name = name;
+ variables[ j ].location = start_index;
+ goto VAR_DONE;
}
- } else {
- int imm = scanvalue();
- if (extra_op == '=') {
- imm_in_mem(mem_index, imm);
- } else if (extra_op == '+') {
- imm(imm);
- swap();
- mem_in_a(mem_index);
- op(add);
- swap();
- imm(mem_index);
- store();
- } else if (extra_op == '-') {
- imm(imm);
- swap();
- mem_in_a(mem_index);
- op(sub);
- swap();
- imm(mem_index);
- store();
- } else if (extra_op == '&') {
- imm(imm);
- swap();
- mem_in_a(mem_index);
- op(and);
- swap();
- imm(mem_index);
- store();
- } else if (extra_op == '!') {
- // @1 != 5; (@1 = !5;)
- imm_in_mem(mem_index, !imm);
+ if (cur.name.len == name.len && strncmp(cur.name.ref, name.ref, name.len) == 0) {
+ run_err(backname_I, "duplicate variable name \"%.*s\"", name.len, name.ref);
}
}
- space;
- checkskip(';', "expected semicolon");
+ run_err(backname_I, "variables count exceeded 1 << 11 (literally how)");
+
+ VAR_DONE:
continue;
}
// register macros
- else if (strncmp("macro", I, 5) == 0 && isspace(I[ 5 ])) {
+ if (strncmp("macro", I, 5) == 0 && isspace(I[ 5 ])) {
I += 6;
space;
// parse macro stuff
@@ -535,7 +521,7 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
}
// emit exit calls
- else if (strncmp("exit", I, 4) == 0) {
+ if (strncmp("exit", I, 4) == 0) {
I += 4;
checkskip('(', "expected open paren on exit blob");
@@ -558,7 +544,7 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
}
// emit system
- else if (strncmp("system", I, 6) == 0 && !isalnum(I[ 6 ])) {
+ if (strncmp("system", I, 6) == 0 && !isalnum(I[ 6 ])) {
I += 6;
space;
checkskip('(', "expected open paren on system blob");
@@ -575,12 +561,12 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
continue;
}
- else if (strncmp("jump", I, 4) == 0 && !isalnum(I[4])) {
+ if (strncmp("jump", I, 4) == 0 && !isalnum(I[4])) {
I += 4;
goto PARSE_JUMP_BLOB;
}
- else if (strncmp("jmp", I, 3) == 0 && !isalnum(I[3])) {
+ if (strncmp("jmp", I, 3) == 0 && !isalnum(I[3])) {
I += 3;
PARSE_JUMP_BLOB:
space;
@@ -630,7 +616,7 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
continue;
}
- else if ((strncmp("jnz", I, 3) == 0 && !isalnum(I[3])) || (strncmp("jz", I, 2) == 0 && !isalnum(I[2]))) {
+ 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";
@@ -638,8 +624,7 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
space;
checkskip('(', "expected open paren on %s blob", name);
space;
- checkskip('@', "expected memory address format as first %s argument (example: `%s(@5, label_name);`)", name, name);
- int target_mem = strtol(I, &I, 10);
+ int target_mem = scanvar();
space;
checkskip(',', "expected comma (second argument) in %s blob (example: `%s(@5, label_name);`)", name, name);
@@ -706,7 +691,7 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
continue;
}
- else if (strncmp("if", I, 2) == 0 && !isalnum(I[2])) {
+ if (strncmp("if", I, 2) == 0 && !isalnum(I[2])) {
// if statement
I += 2;
space; checkskip('(', "expected open paren for if statement"); space;
@@ -733,16 +718,17 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
// completely eliminate code generated in useless if statement
int m2[S/4];
Data = Code = m2;
+ label_t variables_G[ 1 << 5 ];
// get new I location
- string new_I = _ir2(I, macros, labels, forward_refs);
+ string new_I = _ir2(I, macros, labels, forward_refs, variables_G);
I = new_I;
// restore values
Code = Code_B;
Data = Data_B;
} else {
// just... i mean, i guess run the code..?
- string new_I = _ir2(I, macros, labels, forward_refs);
+ string new_I = _ir2(I, macros, labels, forward_refs, variables);
I = new_I;
}
@@ -755,9 +741,7 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
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;
+ int mem_index = scanvar(); space;
checkskip(')', "expected closing paren after if statement argument"); space;
checkskip('{', "expected opening bracket for if statement body"); space;
@@ -771,7 +755,7 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
op(str);
// handle the code stuff
- string new_I = _ir2(I, macros, labels, forward_refs);
+ string new_I = _ir2(I, macros, labels, forward_refs, variables);
I = new_I;
*patchback = Code - m; // patch the jump instruction
@@ -779,7 +763,7 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
continue;
}
- else if (strncmp("while", I, 5) == 0 && !isalnum(I[5])) {
+ if (strncmp("while", I, 5) == 0 && !isalnum(I[5])) {
I += 5;
space; checkskip('(', "expected open paren for while loop"); space;
ir2_depth++;
@@ -806,9 +790,10 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
// completely eliminate code generated in useless while loop
int m2[S/4];
Data = Code = m2;
+ label_t variables_G[ 1 << 5 ];
// get new I location
- string new_I = _ir2(I, macros, labels, forward_refs);
+ string new_I = _ir2(I, macros, labels, forward_refs, variables_G);
I = new_I;
// restore values
Code = Code_B;
@@ -818,7 +803,7 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
int start = Code - m;
- string new_I = _ir2(I, macros, labels, forward_refs);
+ string new_I = _ir2(I, macros, labels, forward_refs, variables);
I = new_I;
imm_in_mem(7, start); // always jump back to the start
@@ -833,9 +818,7 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
I++; space;
}
- checkskip('@', "expected memory address for while loop expression (hint: only simple conditions are supported)");
- if (!isdigit(*I)) run_err(I, "expected memory index");
- int mem_index = strtol(I, &I, 10); space;
+ int mem_index = scanvar(); space;
checkskip(')', "expected closing paren after while loop condition"); space;
checkskip('{', "expected opening bracket for while loop body"); space;
@@ -851,7 +834,7 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
int start_index = Code - m;
// handle the code stuff
- string new_I = _ir2(I, macros, labels, forward_refs);
+ string new_I = _ir2(I, macros, labels, forward_refs, variables);
I = new_I;
*patchback = Code - m; // patch the jump instruction
@@ -869,7 +852,7 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
}
// macro call, maybe?
- else if (isalpha(*I)) {
+ if (isalpha(*I)) {
string old_I = I;
slice_t name = scanword();
space;
@@ -900,6 +883,10 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
continue;
}
+ if (*I != '(') {
+ I = old_I;
+ goto REST_AFTER_MACRO_CALL;
+ }
checkskip('(', "expected open paren after alphanumeric word (assuming this is a blob)");
space;
@@ -1020,13 +1007,122 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
new.ref[ used ] = 0;
- _ir2(new.ref, macros, labels, forward_refs);
+ _ir2(new.ref, macros, labels, forward_refs, variables);
continue;
}
+
+ REST_AFTER_MACRO_CALL:
+
+ // handle assignments!
+ if (varqual(T)) {
+ string starting_qual = I;
+ int mem_index = scanvar();
+ space;
+
+ if(*I == '-' && I[1] == '-') { // decrement
+ I += 2;
+ space;
+ checkskip(';', "expected semicolon");
+ imm(1);
+ swap();
+ mem_in_a(mem_index);
+ op(sub);
+ swap();
+ imm(mem_index);
+ store();
+
+ continue;
+ }
+
+ if(*I == '+' && I[1] == '+') { // increment
+ I += 2;
+ space;
+ checkskip(';', "expected semicolon");
+ imm(1);
+ swap();
+ mem_in_a(mem_index);
+ op(add);
+ swap();
+ imm(mem_index);
+ store();
+
+ continue;
+ }
+
+ char extra_op = '=';
+ if (*I == '+' || *I == '-' || *I == '&' || *I == '!') extra_op = *I++;
+ checkskip('=', "expected assigment after memory blob (hint: only +-&! are supported)");
+ space;
+
+ if (mem_index == 7 && !has_jump_warned) {
+ has_jump_warned = true;
+ printf("\nwarn: writing to memory index 7 is equivalent to a jump\n");
+ printf(" if this behavior is intended, use the jump blob instead.\n\n");
+ }
+
+ if (varqual(*I)) {
+ int mem2_index = scanvar();
+ space;
+
+ if (extra_op == '=') {
+ mov_mem_mem(mem_index, mem2_index);
+ } else if (extra_op == '+') {
+ perform_op(add);
+ } else if (extra_op == '-') {
+ perform_op(sub);
+ } else if (extra_op == '&') {
+ perform_op(and);
+ } else if (extra_op == '!') {
+ // @1 != @2; (@1 = !@2)
+ mem_in_a(mem2_index);
+ op(not);
+ swap();
+ imm(mem_index);
+ store();
+ }
+ } else {
+ int imm = scanvalue();
+
+ if (extra_op == '=') {
+ imm_in_mem(mem_index, imm);
+ } else if (extra_op == '+') {
+ imm(imm);
+ swap();
+ mem_in_a(mem_index);
+ op(add);
+ swap();
+ imm(mem_index);
+ store();
+ } else if (extra_op == '-') {
+ imm(imm);
+ swap();
+ mem_in_a(mem_index);
+ op(sub);
+ swap();
+ imm(mem_index);
+ store();
+ } else if (extra_op == '&') {
+ imm(imm);
+ swap();
+ mem_in_a(mem_index);
+ op(and);
+ swap();
+ imm(mem_index);
+ store();
+ } else if (extra_op == '!') {
+ // @1 != 5; (@1 = !5;)
+ imm_in_mem(mem_index, !imm);
+ }
+ }
+
+ space;
+ checkskip(';', "expected semicolon");
+ continue;
+ }
// unknown
- else run_err(I, "unknown token '%c' (%i)", T, T);
+ run_err(I, "unknown token '%c' (%i)", T, T);
}
return I;
@@ -1035,8 +1131,9 @@ string _ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label
ir2(string I) {
macro_t macros[ 1 << 9 ] = { 0 };
label_t labels[ 1 << 10 ] = { 0 };
+ label_t variables[ 1 << 11 ] = { 0 };
label_delegated_t forward_refs[ 1 << 10 ] = { 0 };
- _ir2(I, macros, labels, forward_refs);
+ _ir2(I, macros, labels, forward_refs, variables);
label_delegated_t *_forward_refs = forward_refs;
// handle forward references!