Ejemplo n.º 1
0
    private MethodBuilder DefineInvokeMethod(TypeBuilder myType, List <BfOp> ops)
    {
        MethodBuilder simpleMethod = myType.DefineMethod("Invoke",
                                                         MethodAttributes.Public | MethodAttributes.Virtual,
                                                         typeof(void),                   // returnType
                                                         new Type[] { typeof(byte[]) }); // ;paramTypes

        ILGenerator generator = simpleMethod.GetILGenerator();

        MethodInfo putcharMI = typeof(BfUtil).GetMethod("PutChar",
                                                        new Type[] { typeof(char) });
        MethodInfo getcharMI = typeof(BfUtil).GetMethod("GetChar",
                                                        new Type[] {});

        Stack <BracketLabels> openBracketStack = new Stack <BracketLabels>();

        LocalBuilder dataptr = generator.DeclareLocal(typeof(int)); // local0: pc
        LocalBuilder tempptr = generator.DeclareLocal(typeof(int)); // local1: temporary

        generator.Emit(OpCodes.Ldc_I4_0);
        generator.Emit(OpCodes.Stloc, dataptr); // dataptr = 0

        for (int pc = 0; pc < ops.Count; ++pc)
        {
            BfOp op = ops[pc];
            switch (op.kind)
            {
            case BfOpKind.INC_PTR:
                generator.Emit(OpCodes.Ldloc, dataptr);
                generator.Emit(OpCodes.Ldc_I4, op.argument);
                generator.Emit(OpCodes.Add);
                generator.Emit(OpCodes.Stloc, dataptr); // dataptr += <op.argument>
                break;

            case BfOpKind.DEC_PTR:
                generator.Emit(OpCodes.Ldloc, dataptr);
                generator.Emit(OpCodes.Ldc_I4, op.argument);
                generator.Emit(OpCodes.Sub);
                generator.Emit(OpCodes.Stloc, dataptr); // dataptr += <op.argument>
                break;

            case BfOpKind.INC_DATA:
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldelem_I4);      // memory[dataptr]
                generator.Emit(OpCodes.Ldc_I4, op.argument);
                generator.Emit(OpCodes.Add);
                generator.Emit(OpCodes.Stelem_I4); // memory[dataptr] += <op.argument>
                break;

            case BfOpKind.DEC_DATA:
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldelem_I4);      // memory[dataptr]
                generator.Emit(OpCodes.Ldc_I4, op.argument);
                generator.Emit(OpCodes.Sub);
                generator.Emit(OpCodes.Stelem_I4); // memory[dataptr] -= <op.argument>
                break;

            case BfOpKind.WRITE_STDOUT:
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldelem_I4);      // memory[dataptr]
                for (int i = 0; i < op.argument; ++i)
                {
                    if (i < op.argument - 1)
                    {
                        generator.Emit(OpCodes.Dup);
                    }
                    generator.EmitCall(OpCodes.Call, putcharMI, null); // putchar(memory[dataptr])
                }
                break;

            case BfOpKind.READ_STDIN:
                for (int i = 0; i < op.argument; ++i)
                {
                    generator.Emit(OpCodes.Ldarg_1);                   // memory
                    generator.Emit(OpCodes.Ldloc, dataptr);            // dataptr
                    generator.EmitCall(OpCodes.Call, getcharMI, null); // getchar()
                    generator.Emit(OpCodes.Stelem_I4);                 // memory[pc] = getchar()
                }
                break;

            case BfOpKind.LOOP_SET_TO_ZERO:
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldc_I4_0);       // 0
                generator.Emit(OpCodes.Stelem_I4);      // memory[dataptr] = 0
                break;

            case BfOpKind.LOOP_MOVE_PTR:
            {
                Label loop    = generator.DefineLabel();
                Label endloop = generator.DefineLabel();
                // Emit a loop that moves the pointer in jumps of op.argument; it's
                // important to do an equivalent of while(...) rather than do...while(...)
                // here so that we don't do the first pointer change if already pointing
                // to a zero.
                //
                // loop:
                //   cmpb 0(%r13), 0
                //   jz endloop
                //   %r13 += argument
                //   jmp loop
                // endloop:
                generator.MarkLabel(loop);
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldelem_I4);      // memory[dataptr]
                generator.Emit(OpCodes.Ldc_I4, 255);
                generator.Emit(OpCodes.And);
                generator.Emit(OpCodes.Ldc_I4_0);       // 0
                generator.Emit(OpCodes.Beq, endloop);   // if memory[dataptr] == 0 goto endloop

                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                if (op.argument < 0)
                {
                    generator.Emit(OpCodes.Ldc_I4, -op.argument);
                    generator.Emit(OpCodes.Sub);
                }
                else
                {
                    generator.Emit(OpCodes.Ldc_I4, op.argument);
                    generator.Emit(OpCodes.Add);
                }
                generator.Emit(OpCodes.Stloc, dataptr); // dataptr += <op.argument>
                generator.Emit(OpCodes.Br, loop);
                generator.MarkLabel(endloop);
            }
            break;

            case BfOpKind.LOOP_MOVE_DATA:
            {
                // Only move if the current data isn't 0:
                //
                //   cmpb 0(%r13), 0
                //   jz skip_move
                //   <...> move data
                // skip_move:
                Label skip_move = generator.DefineLabel();
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldelem_I4);      // memory[dataptr]
                generator.Emit(OpCodes.Ldc_I4, 255);
                generator.Emit(OpCodes.And);
                generator.Emit(OpCodes.Ldc_I4_0); // 0
                generator.Emit(OpCodes.Beq, skip_move);

                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                if (op.argument < 0)
                {
                    generator.Emit(OpCodes.Ldc_I4, -op.argument);
                    generator.Emit(OpCodes.Sub);
                }
                else
                {
                    generator.Emit(OpCodes.Ldc_I4, op.argument);
                    generator.Emit(OpCodes.Add);
                }
                generator.Emit(OpCodes.Stloc, tempptr); // temp = dataptr + <op.argument>

                // Use rax as a temporary holding the value of at the original pointer;
                // then use al to add it to the new location, so that only the target
                // location is affected: addb %al, 0(%r13)
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, tempptr); // temp
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldelem_I4);      // memory[dataptr]
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, tempptr); // temp
                generator.Emit(OpCodes.Ldelem_I4);      // memory[temp]
                generator.Emit(OpCodes.Add);            // memory[dataptr] + memory[temp]
                generator.Emit(OpCodes.Stelem_I4);      // memory[temp] = memory[dataptr] + memory[temp]

                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldc_I4_0);       // 0
                generator.Emit(OpCodes.Stelem_I4);      // memory[dataptr] = 0

                generator.MarkLabel(skip_move);
            }
            break;

            case BfOpKind.JUMP_IF_DATA_ZERO:
            {
                Label openLabel  = generator.DefineLabel();
                Label closeLabel = generator.DefineLabel();
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldelem_I4);      // memory[dataptr]
                generator.Emit(OpCodes.Ldc_I4, 255);
                generator.Emit(OpCodes.And);
                generator.Emit(OpCodes.Ldc_I4_0);        // 0
                generator.Emit(OpCodes.Beq, closeLabel); // if memory[dataptr] == 0 goto closeLabel
                generator.MarkLabel(openLabel);
                openBracketStack.Push(new BracketLabels(openLabel, closeLabel));
            }
            break;

            case BfOpKind.JUMP_IF_DATA_NOT_ZERO:
            {
                if (openBracketStack.Count == 0)
                {
                    BfUtil.DIE($"Unmatched closing ']' at pc={pc}");
                }
                BracketLabels labels = openBracketStack.Pop();
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldelem_I4);      // memory[dataptr]
                generator.Emit(OpCodes.Ldc_I4, 255);
                generator.Emit(OpCodes.And);
                generator.Emit(OpCodes.Ldc_I4_0);                 // 0
                generator.Emit(OpCodes.Bne_Un, labels.openLabel); // if memory[dataptr] != 0 goto openLabel
                generator.MarkLabel(labels.closeLabel);
            }
            break;

            default:
                BfUtil.DIE($"INVALID_OP encountered on pc={pc}");
                break;
            }
        }

        generator.Emit(OpCodes.Ret);

        return(simpleMethod);
    }
Ejemplo n.º 2
0
    private MethodBuilder DefineInvokeMethod(TypeBuilder myType, string instructions)
    {
        MethodBuilder simpleMethod = myType.DefineMethod("Invoke",
                                                         MethodAttributes.Public | MethodAttributes.Virtual,
                                                         typeof(void),                   // returnType
                                                         new Type[] { typeof(byte[]) }); // ;paramTypes

        ILGenerator generator = simpleMethod.GetILGenerator();

        MethodInfo putcharMI = typeof(BfUtil).GetMethod("PutChar",
                                                        new Type[] { typeof(char) });
        MethodInfo getcharMI = typeof(BfUtil).GetMethod("GetChar",
                                                        new Type[] {});

        Stack <BracketLabels> openBracketStack = new Stack <BracketLabels>();

        LocalBuilder dataptr = generator.DeclareLocal(typeof(int)); // local0: pc

        generator.Emit(OpCodes.Ldc_I4_0);
        generator.Emit(OpCodes.Stloc, dataptr); // dataptr = 0

        for (int pc = 0; pc < instructions.Length; ++pc)
        {
            char c = instructions[pc];
            switch (c)
            {
            case '>':
                generator.Emit(OpCodes.Ldloc, dataptr);
                generator.Emit(OpCodes.Ldc_I4_1);
                generator.Emit(OpCodes.Add);
                generator.Emit(OpCodes.Stloc, dataptr); // ++dataptr
                break;

            case '<':
                generator.Emit(OpCodes.Ldloc, dataptr);
                generator.Emit(OpCodes.Ldc_I4_1);
                generator.Emit(OpCodes.Sub);
                generator.Emit(OpCodes.Stloc, dataptr); // --dataptr
                break;

            case '+':
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr);
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldelem_I4);      // memory[dataptr]
                generator.Emit(OpCodes.Ldc_I4_1);
                generator.Emit(OpCodes.Add);
                generator.Emit(OpCodes.Stelem_I4); // memory[dataptr] += 1
                break;

            case '-':
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldelem_I4);      // memory[dataptr]
                generator.Emit(OpCodes.Ldc_I4_1);
                generator.Emit(OpCodes.Sub);
                generator.Emit(OpCodes.Stelem_I4); // memory[pc] -= 1
                break;

            case '.':
                generator.Emit(OpCodes.Ldarg_1);                   // memory
                generator.Emit(OpCodes.Ldloc, dataptr);            // dataptr
                generator.Emit(OpCodes.Ldelem_I4);                 // memory[dataptr]
                generator.EmitCall(OpCodes.Call, putcharMI, null); // putchar(memory[dataptr])
                break;

            case ',':
                generator.Emit(OpCodes.Ldarg_1);                   // memory
                generator.Emit(OpCodes.Ldloc, dataptr);            // dataptr
                generator.EmitCall(OpCodes.Call, getcharMI, null); // getchar()
                generator.Emit(OpCodes.Stelem_I4);                 // memory[dataptr] = getchar()
                break;

            case '[':
            {
                Label openLabel  = generator.DefineLabel();
                Label closeLabel = generator.DefineLabel();
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldelem_I4);      // memory[dataptr]
                generator.Emit(OpCodes.Ldc_I4, 255);
                generator.Emit(OpCodes.And);
                generator.Emit(OpCodes.Ldc_I4_0);        // 0
                generator.Emit(OpCodes.Beq, closeLabel); // if memory[pc] == 0 goto closeLabel
                generator.MarkLabel(openLabel);
                openBracketStack.Push(new BracketLabels(openLabel, closeLabel));
            }
            break;

            case ']':
            {
                if (openBracketStack.Count == 0)
                {
                    BfUtil.DIE($"Unmatched closing ']' at pc={pc}");
                }
                BracketLabels labels = openBracketStack.Pop();
                generator.Emit(OpCodes.Ldarg_1);        // memory
                generator.Emit(OpCodes.Ldloc, dataptr); // dataptr
                generator.Emit(OpCodes.Ldelem_I4);      // memory[dataptr]
                generator.Emit(OpCodes.Ldc_I4, 255);
                generator.Emit(OpCodes.And);
                generator.Emit(OpCodes.Ldc_I4_0);                 // 0
                generator.Emit(OpCodes.Bne_Un, labels.openLabel); // if memory[pc] != 0 goto openLabel
                generator.MarkLabel(labels.closeLabel);
            }
            break;

            default:
                Console.WriteLine("Unhandled instruction: " + c);
                break;
            }
        }

        generator.Emit(OpCodes.Ret);

        return(simpleMethod);
    }