#include #include static int x; static int instruction_start; static int program_start; enum ReturnState { kNormal, kFirstInstructionAfterBranch, kSecondInstructionAfterReturn, kFirstInstructionAfterReturn }; static int return_state = kFirstInstructionAfterBranch; static int stack[540] = {100}, sp = 0; static int length, offset; static jmp_buf j; #define min(a, b) a < b ? a : b static void trace(const char *label, int line) { // printf("%s: line=%d, rs=%d, x=%d, stack[%d]=%d\n", // label, line, return_state, x, // sp, stack[sp]); } static void tracejmp(const char *label, int line, jmp_buf j, int target) { // printf("%s: line=%d, rs=%d, x=%d, stack[%d]=%d, " // "length=%d, offset=%d, target=%d\n", // label, line, return_state, x, // sp, stack[sp], // length, offset, target); longjmp(j, target); } #define z \ case __LINE__: \ (return_state & 1) \ ? /* Unconditionally move to next instruction after branch. */ \ (return_state--, \ (x = 0), \ (void)trace("next", __LINE__), \ (void)(instruction_start = __LINE__ + 1)) \ : (__LINE__ - program_start) % 9 \ ? /* Accumulate. */ \ ((void)(x |= 1 << (__LINE__ - instruction_start)), \ trace("accumulate", __LINE__)) \ : __LINE__ - instruction_start != 17 \ ? /* Output. */ \ (putchar(x), \ (x = 0), \ --stack[sp]) \ ? /* Keep going if there are more bytes to print. */ \ (void)(instruction_start = __LINE__ + 1) \ : /* Pop stack when we have printed enough bytes. */ \ (return_state = kFirstInstructionAfterReturn, \ (sp -= 2), \ tracejmp("return", __LINE__, j, stack[sp + 1])) \ : /* Branch. */ \ ((length = (x & 0xff) + 3), \ (offset = ((x >> 9) + 3) * 9), \ return_state == kSecondInstructionAfterReturn) \ ? (stack[sp] -= length) <= 0 \ ? /* Recursive return. */ \ (return_state = kFirstInstructionAfterReturn, \ (sp -= 2), \ tracejmp("chain_return", __LINE__, j, stack[sp + 1])) \ : /* Completed return chain. */ \ ((return_state = kNormal), \ (instruction_start = __LINE__ + 1), \ (void)trace("end return", __LINE__), \ (void)(x = 0)) \ : /* Initiate branch. */ \ ((stack[sp + 1] = instruction_start - 1), \ (stack[sp + 2] = min(stack[sp], length)), \ (return_state = kFirstInstructionAfterBranch), \ (sp += 2), \ tracejmp("branch", __LINE__, j, __LINE__ - offset)); int main(int argc, char **argv) { switch(setjmp(j)) { default: return_state--; x = 0; program_start = __LINE__ + 1; instruction_start = __LINE__ + 1; // 1 // 2 // 3 z // 4 z // 5 // 6 z // 7 // 8 z // 0 -> "X" z // 1 // 2 // 3 z // 4 z // 5 // 6 z // 7 // 8 z // 0 -> "Y" // 1 z // 2 // 3 z // 4 // 5 // 6 // 7 // 8 z // 0 -> "\n" z // 1 // 2 // 3 z // 4 // 5 // 6 // 7 // 8 // 9 // 10 z // 11 // 12 // 13 // 14 // 15 // 16 // 17 z // 18 -> repeat 12, offset = -3 } }