예제 #1
0
        private static EmitSyntax EmitAst(EmitSyntax emit, AstNode ast, Ref<Args> input)
        {
            var settings = new ILCompilerSettings
            {
                LdInput = il => il.Ldarg(input),
                SUCCESS = emit.Labels.Generate(),
                FAILURE = emit.Labels.Generate(),
            };

            var _ = new ILNfaCompiler(ast, emit, settings);

            emit
                .Label(settings.SUCCESS)
                .Ldc_I4_1()
                .Ret()
                .Label(settings.FAILURE)
                .Ldc_I4_0()
                .Ret();

            return emit;
        }
예제 #2
0
        public ILNfaCompiler(AstNode node, EmitSyntax emit, ILCompilerSettings settings)
        {
            this.Scanner = new StemScanner();

            this.emit = emit;
            this.settings = settings;

            var labels = emit.Labels;
            NEXT_THREAD     = labels.Generate();
            RESUME_ALL      = labels.Generate();
            NEXT_INPUT      = labels.Generate();
            THREAD_SUSPEND  = labels.Generate();
            THREAD_DISPATCH = labels.Generate();

            var LABEL0      = labels.Generate();
            var LABEL1      = labels.Generate();
            var POSTCOMPILEINIT = labels.Generate();
            var POSTCOMPILEINIT_BACK = labels.Generate();

            var locals = emit.Locals;
            slots        = locals.Generate();
            labelIndexToLocation = locals.Generate();
            intTmp       = locals.Generate();
            threadTmp    = locals.Generate();

            INfaVM code = this;

            this.inputPump = new ArrayLoopGenerator(
                       valueType: emit.Types.Int32,
                       ldarray:   settings.LdInput,
                       body:
                           il => il
                               .Do(matchedStack.Clear)
                               .Br(RESUME_ALL.GetRef())
                        );

            this.runningStack   = new StackGenerator(emit, typeof(Thread));
            this.suspendedStack = new StackGenerator(emit, typeof(Thread));
            this.matchedStack   = new StackGenerator(emit, typeof(Thread));
            this.tmpStack       = new StackGenerator(emit, typeof(Thread), nullContainer: true);

            emit
                .Local(intTmp, emit.Types.Int32)
                .Local(slots, emit.Types.Import(typeof(int[])))
                .Local(labelIndexToLocation, emit.Types.Import(typeof(int[])))
                .Br(POSTCOMPILEINIT.GetRef())
                .Label(POSTCOMPILEINIT_BACK)
                .Local(threadTmp, emit.Types.Import(typeof(Thread)))
                .Ldloca(threadTmp.GetRef())
                .Initobj(emit.Types.Import(typeof(Thread)))
                .Do(inputPump.EmitInitialization)
                ;

            new RegularNfaVMCompiler().Compile(node, code);

            int LabelCount = Math.Max(1, indexToLabel.Count);

            this.runningStack.SetSize(LabelCount);
            this.suspendedStack.SetSize(LabelCount);
            this.matchedStack.SetSize(LabelCount);
            this.tmpStack.SetSize(LabelCount);

            emit
                .Label(POSTCOMPILEINIT)
                .Do(runningStack.Init)
                .Do(suspendedStack.Init)
                .Do(matchedStack.Init)
                .Do(tmpStack.Init)
                .Ldc_I4(slotCount)
                .Newarr(emit.Types.Int32)
                .Stloc(slots.GetRef())

                .Ldc_I4(LabelCount)
                .Newarr(emit.Types.Int32)
                .Stloc(labelIndexToLocation.GetRef())
                // Fill labelIndexToLocation with -1 :
                .Ldc_I4(LabelCount).Stloc(intTmp.GetRef())

                .Label(LABEL1)
                .Ldloc(intTmp.GetRef())
                .Ldc_I4_0()
                .Beq(LABEL0.GetRef())
                .Ldloc(intTmp.GetRef())
                .Ldc_I4(1)
                .Sub()
                .Stloc(intTmp.GetRef())
                .Ldloc(labelIndexToLocation.GetRef())
                .Ldloc(intTmp.GetRef())
                .Ldc_I4(int.MinValue)
                .Stelem_I4()
                .Br(LABEL1.GetRef())
                .Label(LABEL0)
                .Br(POSTCOMPILEINIT_BACK.GetRef());

            // Save thread as suspended (stack should already contain label index to suspend)
            emit.Label(THREAD_SUSPEND);
            StThreadValueByRuntimeLabelIndex();
            emit
                // Don't add thread if same thread (same label index
                // with current input location) already exists in a list.
                .Ldloc(labelIndexToLocation.GetRef())
                .Ldloca(threadTmp.GetRef())
                .Ldfld(LabelIndexField)
                .Ldelem_I4()
                .Ldloc(inputPump.Index.GetRef())
                .Beq(NEXT_THREAD.GetRef())

                // Mark label index as visited
                .Ldloc(labelIndexToLocation.GetRef())
                .Ldloca(threadTmp.GetRef())
                .Ldfld(LabelIndexField)
                .Ldloc(inputPump.Index.GetRef())
                .Stelem_I4()
                ;

            suspendedStack.PushFrom(emit, threadTmp);

            emit
                .Br(NEXT_THREAD.GetRef())

                .Label(RESUME_ALL)
                .Swap(suspendedStack.Stack, runningStack.Stack, tmpStack.Stack)
                .Swap(suspendedStack.Index, runningStack.Index, tmpStack.Index)
                .Label(NEXT_THREAD)
                ;

            runningStack
                .StackLoop(
                    emit,
                    (emit2, thread) =>
                    {
                        emit2
                            .Ldloca(thread.GetRef())
                            .Ldfld(LabelIndexField)
                            .Label(THREAD_DISPATCH)
                            .Switch(indexToLabel.Select(def => def.GetRef()).ToArray())
                            .Br(settings.FAILURE.GetRef());
                    })
                    ;
            emit
                .Br(NEXT_INPUT.GetRef())
                ;

            emit
                .Label(NEXT_INPUT)
                ;

            inputPump.EmitLoopPass(emit, false);

            emit
                // Check if there are matched threads:
                .Do(matchedStack.LdCount)
                .Ldc_I4_0()
                .Beq(settings.FAILURE.GetRef())
                .Br(settings.SUCCESS.GetRef());
        }
예제 #3
0
        public ILNfaCompiler(AstNode node, EmitSyntax emit, ILCompilerSettings settings)
        {
            this.Scanner = new StemScanner();

            this.emit     = emit;
            this.settings = settings;

            var labels = emit.Labels;

            NEXT_THREAD     = labels.Generate();
            RESUME_ALL      = labels.Generate();
            NEXT_INPUT      = labels.Generate();
            THREAD_SUSPEND  = labels.Generate();
            THREAD_DISPATCH = labels.Generate();

            var LABEL0               = labels.Generate();
            var LABEL1               = labels.Generate();
            var POSTCOMPILEINIT      = labels.Generate();
            var POSTCOMPILEINIT_BACK = labels.Generate();

            var locals = emit.Locals;

            slots = locals.Generate();
            labelIndexToLocation = locals.Generate();
            intTmp    = locals.Generate();
            threadTmp = locals.Generate();


            INfaVM code = this;

            this.inputPump = new ArrayLoopGenerator(
                valueType: emit.Types.Int32,
                ldarray:   settings.LdInput,
                body:
                il => il
                .Do(matchedStack.Clear)
                .Br(RESUME_ALL.GetRef())
                );

            this.runningStack   = new StackGenerator(emit, typeof(Thread));
            this.suspendedStack = new StackGenerator(emit, typeof(Thread));
            this.matchedStack   = new StackGenerator(emit, typeof(Thread));
            this.tmpStack       = new StackGenerator(emit, typeof(Thread), nullContainer: true);

            emit
            .Local(intTmp, emit.Types.Int32)
            .Local(slots, emit.Types.Import(typeof(int[])))
            .Local(labelIndexToLocation, emit.Types.Import(typeof(int[])))
            .Br(POSTCOMPILEINIT.GetRef())
            .Label(POSTCOMPILEINIT_BACK)
            .Local(threadTmp, emit.Types.Import(typeof(Thread)))
            .Ldloca(threadTmp.GetRef())
            .Initobj(emit.Types.Import(typeof(Thread)))
            .Do(inputPump.EmitInitialization)
            ;

            new RegularNfaVMCompiler().Compile(node, code);

            int LabelCount = Math.Max(1, indexToLabel.Count);

            this.runningStack.SetSize(LabelCount);
            this.suspendedStack.SetSize(LabelCount);
            this.matchedStack.SetSize(LabelCount);
            this.tmpStack.SetSize(LabelCount);

            emit
            .Label(POSTCOMPILEINIT)
            .Do(runningStack.Init)
            .Do(suspendedStack.Init)
            .Do(matchedStack.Init)
            .Do(tmpStack.Init)
            .Ldc_I4(slotCount)
            .Newarr(emit.Types.Int32)
            .Stloc(slots.GetRef())

            .Ldc_I4(LabelCount)
            .Newarr(emit.Types.Int32)
            .Stloc(labelIndexToLocation.GetRef())
            // Fill labelIndexToLocation with -1 :
            .Ldc_I4(LabelCount).Stloc(intTmp.GetRef())

            .Label(LABEL1)
            .Ldloc(intTmp.GetRef())
            .Ldc_I4_0()
            .Beq(LABEL0.GetRef())
            .Ldloc(intTmp.GetRef())
            .Ldc_I4(1)
            .Sub()
            .Stloc(intTmp.GetRef())
            .Ldloc(labelIndexToLocation.GetRef())
            .Ldloc(intTmp.GetRef())
            .Ldc_I4(int.MinValue)
            .Stelem_I4()
            .Br(LABEL1.GetRef())
            .Label(LABEL0)
            .Br(POSTCOMPILEINIT_BACK.GetRef());

            // Save thread as suspended (stack should already contain label index to suspend)
            emit.Label(THREAD_SUSPEND);
            StThreadValueByRuntimeLabelIndex();
            emit
            // Don't add thread if same thread (same label index
            // with current input location) already exists in a list.
            .Ldloc(labelIndexToLocation.GetRef())
            .Ldloca(threadTmp.GetRef())
            .Ldfld(LabelIndexField)
            .Ldelem_I4()
            .Ldloc(inputPump.Index.GetRef())
            .Beq(NEXT_THREAD.GetRef())

            // Mark label index as visited
            .Ldloc(labelIndexToLocation.GetRef())
            .Ldloca(threadTmp.GetRef())
            .Ldfld(LabelIndexField)
            .Ldloc(inputPump.Index.GetRef())
            .Stelem_I4()
            ;

            suspendedStack.PushFrom(emit, threadTmp);

            emit
            .Br(NEXT_THREAD.GetRef())

            .Label(RESUME_ALL)
            .Swap(suspendedStack.Stack, runningStack.Stack, tmpStack.Stack)
            .Swap(suspendedStack.Index, runningStack.Index, tmpStack.Index)
            .Label(NEXT_THREAD)
            ;

            runningStack
            .StackLoop(
                emit,
                (emit2, thread) =>
            {
                emit2
                .Ldloca(thread.GetRef())
                .Ldfld(LabelIndexField)
                .Label(THREAD_DISPATCH)
                .Switch(indexToLabel.Select(def => def.GetRef()).ToArray())
                .Br(settings.FAILURE.GetRef());
            })
            ;
            emit
            .Br(NEXT_INPUT.GetRef())
            ;

            emit
            .Label(NEXT_INPUT)
            ;

            inputPump.EmitLoopPass(emit, false);

            emit
            // Check if there are matched threads:
            .Do(matchedStack.LdCount)
            .Ldc_I4_0()
            .Beq(settings.FAILURE.GetRef())
            .Br(settings.SUCCESS.GetRef());
        }