diff options
Diffstat (limited to 'pu2/pu2.c')
| -rw-r--r-- | pu2/pu2.c | 405 |
1 files changed, 251 insertions, 154 deletions
@@ -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! |
