int main(int argc, char** argv) { /* * These counters will be used as offsets for messages when using pipes * i.e. write(stack + stack_pos, strlen(stack + stack_pos)) */ int stack_pos = 0; int input_pos = 1; char input[MAX_BUF_SIZE] = ""; char stack[MAX_BUF_SIZE] = ""; char result[MAX_BUF_SIZE] = ""; fgets(input, MAX_BUF_SIZE - 1, stdin); fgets(stack, MAX_BUF_SIZE - 1, stdin); fgets(result, MAX_BUF_SIZE - 1, stdin); input[strcspn(input, "\n")] = 0; stack[strcspn(stack, "\n")] = 0; result[strcspn(result, "\n")] = 0; if ((strlen(input) == 0)) // End of input, clearing stack { while (stack_pos < strlen(stack)) { write_to_result(result, ' '); write_to_result(result, stack[stack_pos++]); } if (debug) fprintf(stderr, "pid: %d end of input! result: %s \n", getpid(), result ); printf("%s", result); return 0; } if (debug) fprintf(stderr, "pid: %d input[0]: %c stack: %s result: %s \n", getpid(), input[0], stack, result ); switch (input[0]) { case '-': /* Odp.: Przez liczbę całkowitą należy rozumież liczbę całkowitą bez znaku */ case '^': case '*': case '/': case '+': while (stack_pos < strlen(stack)) { /* treating every op as left-associative */ if (op_priority(input[0]) <= op_priority(stack[stack_pos])) { write_to_result(result, ' '); write_to_result(result, stack[stack_pos++]); } else break; } write_to_result(result, ' '); case '(': write_to_stack(stack, input[0], &stack_pos); break; case ')': while(stack_pos <= strlen(stack)) { if (stack[stack_pos] != '(') { write_to_result(result, ' '); write_to_result(result, stack[stack_pos++]); } else { stack_pos++; break; } } case ' ': case '\n': break; default: add_space_to_result(result); /* * We only checked first character of expression (input[0]) * Now let's check if there are other characters in expression */ for (int i = 0; i < strlen(input); i++) { /* When there's no space around parenthesis * easier testing */ if (!isspace(input[i]) && (input[i] != ')')) { write_to_result(result, input[i]); } else { input_pos = i + ((input[i] != ')') ? (1) : (0)); break; } } break; } /* Moving offset to first nonwhite character in input */ while ((input_pos < strlen(input)) && (isspace(input[input_pos]))) input_pos++; spawn_worker(input + input_pos, stack + stack_pos, result); return 0; }
int main(int argc, char **argv) { FILE *file; char instruction; char* filename; struct vector instruction_stream; if(argc != 2) { /* wrong number of args */ fprintf(stderr, "Error: exactly 1 HQ9+ source file as arg required\n"); exit(EXIT_FAILURE); } /* open file */ filename = argv[1]; file = fopen(filename, "r"); if (file == NULL) { /* could not open file */ perror("Error opening file"); exit(EXIT_FAILURE); } /*** prologue ***/ vector_create(&instruction_stream, 100); char prologue [] = { 0x55, // push %rbp 0x48, 0x89, 0xE5, // mov %rsp, %rbp // backup %r12 (callee saved register) 0x41, 0x54, // pushq %r12 // store %rdi content (putchar) in %r12 as callee saved 0x49, 0x89, 0xFC, // movq %rdi, %r12 // push accumulator on stack 0x6a, 0x00, // pushq $0 }; vector_push(&instruction_stream, prologue, sizeof(prologue)); int stack_offset = -0x10; // offset from %rbp int offset_accumulator = stack_offset; // accumulator address: -0x10(%rbp) // hello world write_to_stack(&instruction_stream, "Hello World\n", &stack_offset); int offset_hello_world = stack_offset; // source code char* source_code = get_source_code(filename); write_to_stack(&instruction_stream, source_code, &stack_offset); free(source_code); int offset_source = stack_offset; // lyrics char* lyrics = get_lyrics(99); write_to_stack(&instruction_stream, lyrics, &stack_offset); free(lyrics); int offset_bottles = stack_offset; // everything after accumulator is text bytes int text_bytes_on_stack = -(stack_offset - offset_accumulator); /*** parse file ***/ while((instruction = fgetc(file)) != EOF) { switch (instruction) { case 'H': { // access single chars of int char *hw = (char*) &offset_hello_world; char opcodes [] = { 0xB0, 00, // movb $0, %al 0x48, 0x8D, 0xBD, hw[0], hw[1], hw[2], hw[3], // leaq -0x<offset>(%rbp),%rdi 0x41, 0xFF, 0xD4 // callq *%r12 }; vector_push(&instruction_stream, opcodes, sizeof(opcodes)); } break; case 'Q': { // access single chars of int char *s = (char*) &offset_source; char opcodes [] = { 0xB0, 00, // movb $0, %al 0x48, 0x8D, 0xBD, s[0], s[1], s[2], s[3], // leaq -0x<offset>(%rbp),%rdi 0x41, 0xFF, 0xD4 // callq *%r12 }; vector_push(&instruction_stream, opcodes, sizeof(opcodes)); } break; case '9': { // access single chars of int char *b = (char*) &offset_bottles; char opcodes [] = { 0xB0, 00, // movb $0, %al 0x48, 0x8D, 0xBD, b[0], b[1], b[2], b[3], // leaq -0x<offset>(%rbp),%rdi // 0xBF, 0x39, 0x00, 0x00, 0x00, // mov $0x39, %edi 0x41, 0xFF, 0xD4 // callq *%r12 }; vector_push(&instruction_stream, opcodes, sizeof(opcodes)); } break; case '+': { char *acc = (char*) &offset_accumulator; char opcodes [] = { // increment the accumulator // TODO from variable instead of constant offset 0x48, 0xFF, 0x45, 0xF0, // incq -0x10(%rbp) }; vector_push(&instruction_stream, opcodes, sizeof(opcodes)); } break; } } if (!feof(file)) { perror("Error reading file"); } fclose(file); /*** epilogue ***/ // access single chars of long char *t = (char*) &text_bytes_on_stack; char epilogue [] = { // free strings 0x48, 0x81, 0xC4, t[0], t[1], t[2], t[3], // addq $<x>, %rsp // free accumulator 0x48, 0x83, 0xC4, 0x08, // addq $8, %rsp // restore callee saved register 0x41, 0x5C, // popq %r12 0x5d, // pop rbp 0xC3 // ret }; vector_push(&instruction_stream, epilogue, sizeof(epilogue)); /*** invoke generated code ***/ /* allocate and copy instruction stream into executable memory */ void* mem = mmap(NULL, instruction_stream.size, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); memcpy(mem, instruction_stream.data, instruction_stream.size); /* typecast memory to a function pointer and call the dynamically created executable code */ void (*hq9p_program) (fn_printf) = mem; hq9p_program(printf); /* clear up */ munmap(mem, instruction_stream.size); vector_destroy(&instruction_stream); exit(EXIT_SUCCESS); }