#include #include #include int main (int argc, char *argv[]) { compiler comp; // compile a named file "-" is stdin comp.compile (argc > 1 ? argv[1] : "-"); // do some semantic checks such as whether all used // instructions actually exist, whether all arguments // are correctly typed, whether comp.check (); // store the parse tree into a string and load it back // to test whether serialisation works // deserialisation, by the way, generates the same AST the // parser did, so comp.check () could be done again to verify // the byte-code comp.load (comp.store ()); // print out the AST in the same format it was read // (lightning asm). this output could be stored to a file // and is basically a disassembly of the byte-code std::cout << "Printing the parse tree back into lightning-asm:\n"; std::cout << "------------------------------------------------\n"; comp.print (std::cout); // assembler is an object whose only job is to transform // lightning-asm to machine code. it utilises lightning's // jit_* macros to do so assembler as; // generate machine code comp.assemble (as); // print a disassembly of the generated code to stdout std::cout << "\nPrinting a disassembly of the machine code:\n"; std::cout << "-------------------------------------------\n"; as.disassemble (std::cout); // assembler::cast can cast to any pointer type. before it does // so, it calls jit::flush_code. int (*func) (int) = as.cast (); // call the function std::cout << "\nCalling the function:\n"; std::cout << "---------------------\n"; std::cout << func (32) << '\n'; return 0; } /* This is the input file I fed it: # mnemonic op1 op2 op3 ret prolog 1 arg_ui => $in getarg_ui %v0, $in # V0 = n blti_ui !forward, %v0, 2 => @ref # If V0 < 2, jump subi_ui %v1, %v0, 1 # V1 = n - 1 subi_ui %v2, %v0, 2 # V2 = n - 2 prepare_i 1 # Prepare for a call with one argument pusharg_ui %v1 # Push the argument finish @self # The self-pointer is a pointer to the # beginning of the code block (entry point). # This instruction jumps to the beginning of the # code, causing recursion retval_i %v1 # Store the result in V1 prepare_i 1 # Another pusharg_ui %v2 # recursive finish @self # call retval_i %v2 # Store the result in V2 addi_ui %v1, %v1, 1 # V1++ addr_ui %ret, %v1, %v2 # RET = V1 + V2 ret # Return patch @ref # Patch jump, we get here if V0 was < 2 movi_i %ret, 1 # RET = 1 ret # Return */ /* This is the output of the program on my x86_64 machine: Printing the parse tree back into lightning-asm: ------------------------------------------------ prolog 1 arg_ui => $in getarg_ui %v0, $in blti_ui !forward, %v0, 2 => @ref subi_ui %v1, %v0, 1 subi_ui %v2, %v0, 2 prepare_i 1 pusharg_ui %v1 finish @self retval_i %v1 prepare_i 1 pusharg_ui %v2 finish @self retval_i %v2 addi_ui %v1, %v1, 1 addr_ui %ret, %v1, %v2 ret patch @ref movi_i %ret, 1 ret Printing a disassembly of the machine code: ------------------------------------------- 0000000000000000 53 push %rbx 0000000000000001 41 54 push %r12 0000000000000003 41 55 push %r13 0000000000000005 55 push %rbp 0000000000000006 48 89 e5 mov %rsp, %rbp 0000000000000009 89 fb mov %edi, %ebx 000000000000000b 83 fb 02 cmp $0x2, %ebx 000000000000000e 0f 82 55 00 00 00 jb 0x69 0000000000000014 8d 73 ff lea -0x1(%rbx), %esi 0000000000000017 8d 7b fe lea -0x2(%rbx), %edi 000000000000001a 49 89 f0 mov %rsi, %r8 000000000000001d 49 bb 48 3a 1f 8d ff 7f mov $0x7fff8d1f3a48, %r11 - 00 00 0000000000000027 49 89 f4 mov %rsi, %r12 000000000000002a 49 89 fd mov %rdi, %r13 000000000000002d 4c 89 c7 mov %r8, %rdi 0000000000000030 49 ff d3 callq %r11 0000000000000033 4c 89 e6 mov %r12, %rsi 0000000000000036 4c 89 ef mov %r13, %rdi 0000000000000039 89 c6 mov %eax, %esi 000000000000003b 49 89 f8 mov %rdi, %r8 000000000000003e 49 bb 48 3a 1f 8d ff 7f mov $0x7fff8d1f3a48, %r11 - 00 00 0000000000000048 49 89 f4 mov %rsi, %r12 000000000000004b 49 89 fd mov %rdi, %r13 000000000000004e 4c 89 c7 mov %r8, %rdi 0000000000000051 49 ff d3 callq %r11 0000000000000054 4c 89 e6 mov %r12, %rsi 0000000000000057 4c 89 ef mov %r13, %rdi 000000000000005a 89 c7 mov %eax, %edi 000000000000005c 83 c6 01 add $0x1, %esi 000000000000005f 8d 04 3e lea (%rsi,%rdi), %eax 0000000000000062 5d pop %rbp 0000000000000063 41 5d pop %r13 0000000000000065 41 5c pop %r12 0000000000000067 5b pop %rbx 0000000000000068 c3 ret 0000000000000069 b8 01 00 00 00 mov $0x1, %eax 000000000000006e 5d pop %rbp 000000000000006f 41 5d pop %r13 0000000000000071 41 5c pop %r12 0000000000000073 5b pop %rbx 0000000000000074 c3 ret Calling the function: --------------------- 7049155 */