/// <summary> /// Create the appropriate element and the appropriate quantifier /// </summary> /// <param name="Item">The elemen to compile</param> /// <param name="Parent">The parent parsed block</param> /// <param name="Compiled">The parent compiled block</param> private void CompileElement(Parse.Element Item, Parse.Block Parent, Block Compiled) { //Just create a NOP for a null item if (Item == null) { Compiled.AddItem(new NOP()); return; } //Anotate Item's commands if (Output != null) Item.Annotation.CompiledPosition.Begin = Output.Length; _OutIdent++; OutComment(Item.GetType().Name + Item.Quantifier); //Check for quantifier QuantifierBefore qb = null; if (!Item.Quantifier.IsDefault()) { if (Item.Quantifier.IsIfAny()) { //Nothing, just add NOP after } else if (Item.Quantifier.IsAsMany() && !Item.Quantifier.Additive) { //Nothing, just add a ConditionalJump after } else if (Item.Quantifier.IsNever()) { //Nothing, add a Fail and a NOP after } else { qb = new QuantifierBefore(Item.Quantifier); Compiled.AddItem(qb); } } int first_runnable_execution_index = Compiled.Count; //Find item's type if (Item is Parse.Block) { Parse.Block pabl = (Parse.Block)Item; Block bl; //New block if it is unnamed, or get the stub if (pabl.Name == null) bl = new Block(this); else bl = _BlocksByName[pabl.Name]; //Compile it CompileBlock(pabl, bl); //Create a call to the block Compiled.AddItem(new CallBlock(bl.ExecuteBlock)); //Update it's index bl.ExecuteIndex = Compiled.Items[first_runnable_execution_index]; } else if (Item is Parse.TextSearch) CETextSearch((Parse.TextSearch) Item, Parent, Compiled); else if (Item is Parse.Literal) CELiterall((Parse.Literal) Item, Compiled); else if (Item is Parse.Variable) CEVariable((Parse.Variable) Item, Parent, Compiled); else if (Item is Parse.ControlFlow) CEControlFlow((Parse.ControlFlow) Item, Parent, Compiled); else if (Item is Parse.FunctionCall) CEFunctionCall((Parse.FunctionCall) Item, Parent, Compiled); else if (Item is Parse.BinaryOperator) CEBinaryOperator((Parse.BinaryOperator) Item, Parent, Compiled); else { Compiled.AddItem(new NOP()); ThrowParseError("Unkown type " + Item.GetType().Name, Item.Annotation.SourcePosition); } int last_runnable_execute_index = Compiled.Count - 1; //Check for quantifier if (!Item.Quantifier.IsDefault()) { if (Item.Quantifier.IsIfAny()) { //On failure jump here var nop = new NOP(); Compiled.AddItem(nop); //Update Runnables CESetOnJumpFailTo(Compiled, first_runnable_execution_index, last_runnable_execute_index, nop); } else if (Item.Quantifier.IsAsMany() && !Item.Quantifier.Additive) { //On failure jump here var cj = new ConditionalJump(Compiled.Items[first_runnable_execution_index]); Compiled.AddItem(cj); //Update Runnables CESetOnJumpFailTo(Compiled, first_runnable_execution_index, last_runnable_execute_index, cj); } else if (Item.Quantifier.IsNever()) { //Fail if the item succeeds Compiled.AddItem(new ReturnBlock(0, false)); //On failure jump here var nop = new NOP(); Compiled.AddItem(nop); //Update Runnables CESetOnJumpFailTo(Compiled, first_runnable_execution_index, last_runnable_execute_index, nop); } else { //On failure jump here var qa = new QuantifierAfter(qb); Compiled.AddItem(qa); //Update Runnables CESetOnJumpFailTo(Compiled, first_runnable_execution_index, last_runnable_execute_index, qa); } } //Anotate Item's commands if (Output != null) Item.Annotation.CompiledPosition.End = Output.Length; _OutIdent--; Item.Annotation.FirstRunnable = Compiled.Items[first_runnable_execution_index]; Item.Annotation.RunnablesCount = Compiled.Count - first_runnable_execution_index; Item.Annotation.RunnableParentBlock = Compiled.ExecuteBlock; for (int i = first_runnable_execution_index ; i < Compiled.Count ; i++) { var rn = Compiled.Items[i]; if (rn.Annotation.Element == null) { rn.Annotation.Element = Item; rn.Annotation.SourcePosition = Item.Annotation.SourcePosition; rn.Annotation.TreeViewNode = Item.Annotation.TreeViewNode; } } IDE.CompiledAnnotations.Add(Item.Annotation.CompiledPosition, Item.Annotation); }
private void CompileBlock(Parse.Block Item, Block Compiled) { //Don't try to compile it twice if (Compiled.Compiled) return; _BlocksByParse.Add(Item, Compiled); Compiled.Compiled = true; Compiled.ExecuteBlock.Name = Item.Name; //Assembly output _OutIdent++; if (Item.Name != null) OutComment("#" + Item.Name + "#"); else OutComment("(unnamed)"); //Compile elements if (Item.Type == Parse.Block.eType.For) { //Just before the loop increment Runnable forContinue = new NOP(); Compiled.ForContinue = forContinue; //When the initializer or loop increment fail succeed Runnable onInitIncrFail = new ReturnBlock(1, true); //First item of loop's body Runnable loopFirst; //Keep track the first and last runnables of current element int this_exec_begin, this_exec_end; this_exec_begin = Compiled.Count; //Compile the initializer CompileElement(Item.Elements[0], Item, Compiled); this_exec_end = Compiled.Count; //Set the on fail for (int i = this_exec_begin; i < this_exec_end; i++) { var it = Compiled.Items[i]; if (it.OnFailJumpTo == null) it.OnFailJumpTo = onInitIncrFail; } this_exec_begin = Compiled.Count; //Compile the loop body CompileElement(Item.Elements[2], Item, Compiled); loopFirst = Compiled.Items[this_exec_begin]; this_exec_begin = Compiled.Count; //Compile the loop increment Compiled.AddItem(forContinue); CompileElement(Item.Elements[1], Item, Compiled); this_exec_end = Compiled.Count; //Set the on fail for (int i = this_exec_begin; i < this_exec_end; i++) { var it = Compiled.Items[i]; if (it.OnFailJumpTo == null) it.OnFailJumpTo = onInitIncrFail; } //Put the continue command var cont = new GoToBlock(0, 1, new[]{loopFirst}); Compiled.AddItem(cont); //Put the on fail Compiled.AddItem(onInitIncrFail); } else { //Keep track the first and last runnables of current and previous element int this_exec_begin, this_exec_end; int prev_exec_begin = 0, prev_exec_end = 0; Runnable this_exec_first; for (int i = 0; i < Item.Elements.Count; i++) { this_exec_begin = Compiled.Count; //Compile the element CompileElement(Item.Elements[i], Item, Compiled); this_exec_end = Compiled.Count; //Put jumps if it is multi (except on the last part) if ((Item.Type == Parse.Block.eType.Multi)) { //Succeed if (i != (Item.Elements.Count - 1)) Compiled.AddItem(new ReturnBlock(1, true)); this_exec_first = Compiled.Items[this_exec_begin]; //Update elements to jump to next on fail if (i != 0) for (int j = prev_exec_begin; j < prev_exec_end; j++) if (Compiled.Items[j].OnFailJumpTo == null) Compiled.Items[j].OnFailJumpTo = this_exec_first; } prev_exec_begin = this_exec_begin; prev_exec_end = this_exec_end; } } //Move elements to Execute.Block Compiled.Done(); _OutIdent--; }