public override BaseNode GetNextNode(Executer exec, BaseNode alreadyUsedChildNode, object nodesResult) { //Hmm, could I execute the if-statement directly here? Must I really wait //for executer to execute it and then proceed based on the result?? //I'll go for direct if-clause execution for now: if (alreadyUsedChildNode == null) { // if (this.m_ifExpression==null || Convert.ToInt32(this.m_ifExpression.Evaluate(exec)) != 0) if (this.m_ifExpression==null || Convert.ToInt32(this.m_ifExpression.Evaluate(exec).GetUnboxed(exec)) != 0) return (BaseNode)this.FirstChild; if (this.m_nextIfNode!=null) return this.m_nextIfNode; return null; } return base.GetNextNode(exec, alreadyUsedChildNode, nodesResult); // int nIndex = this.ChildNodes.IndexOfValue(alreadyUsedChildNode); // if (nIndex == 0) //it was the "if" clause // { // if ((int)((Types.Object)nodesResult).GetUnboxed() != 0) // return (BaseNode)this.ChildNodes.GetByIndex(2); //this is where the statements begin if it's true // if (this.ChildNodes.Count > 1) // return (BaseNode)this.ChildNodes.GetByIndex(1); // } // return null; }
public virtual BaseNode GetNextNode(Executer exec, BaseNode alreadyUsedChildNode, object nodesResult) { if (alreadyUsedChildNode != null) return (BaseNode)alreadyUsedChildNode.NextSibling; if (this.HasChildNodes) return (BaseNode)this.FirstChild; return null; }
public void Rewind() { //EH.Put("Rewind called"); MethodNode nodeToExecute = null; if (this.m_callStack != null) { //find first item in stack (i.e., the first called method) while (this.m_callStack.Count > 1) this.m_callStack.Pop(); nodeToExecute = (MethodNode)this.m_callStack.Pop(); } this.m_callStack = new System.Collections.Stack(); this.m_valueStack = new System.Collections.ArrayList(); this.m_currentNode = null; if (nodeToExecute != null) this.m_callStack.Push(nodeToExecute); }
private static bool HandleNodeBorderChars(string sDividerChar, ref BaseNode currentNode) { if (sDividerChar == "{" || sDividerChar == "}") { if (sDividerChar == "{") { bool bCreateNewUndefinedNode = true; //if there's a { in the middle of the code, with nothing special preceding it, (if,for etc) //let's just create a chunkNode for it. // if (currentNode.GetType() == typeof(MethodNode)) // //Metho // bCreateNewUndefinedNode = false; // else // { try { //if we're in a chunk node which is supposed to close automatically after one line, like: // if(true) x=1; //and instead we encounter a {, like: // if(true) { //that means it should NOT close automatically. ChunkNode chunkNode = (ChunkNode)currentNode; if (chunkNode.CloseNodeAfterNextLine) { chunkNode.CloseNodeAfterNextLine = false; bCreateNewUndefinedNode = false; } } catch {} // } if (bCreateNewUndefinedNode) { ChunkNode newChunkNode = new ChunkNode(); currentNode.AppendChild("undef", newChunkNode); currentNode = newChunkNode; } } else // "}" currentNode = (BaseNode)currentNode.ParentNode; return true; } return false; }
public static ClassNode Parse(string sScript) { ArrayList aAllLines = new ArrayList(); string[] aKeywords = new string[]{"for", "else if", "if", "else", "while", "goto", "gosub", "return"}; //TODO: I don't handle keyword and a statement on the same line right now- //e.g. "if (true) blabla();" or "for (;;) put(1);" BaseNode rootNode = new BaseNode(); ClassNode classNode = new ClassNode(); rootNode.AppendChild("Class_01", classNode); BaseNode currentNode = classNode; //easier parsing if \r\n is replaced by \n sScript = sScript.Replace("\r\n", "\n"); //also a little easier if script always ends with a \n if (!sScript.EndsWith("\n")) sScript+="\n"; //structure will be [ScriptName:[MethodName:[LabelName:[clause:[clause]]]]] //Labels must be on top level in a method (e.g. not inside an if(){} clause) while (sScript.Length > 0) { //first divide into "lines" - EndOfLine represented by: return ; { or } string sLine = ""; string sDividerChar = ""; MatchCollection matches = Regex.Matches(sScript, "[^{};\\n]*[{};\\n]"); foreach (Match m in matches) { sLine = sScript.Substring(0, m.Index+m.Length); sDividerChar = m.Value.Substring(m.Value.Length-1,1); if (sDividerChar == ";") { //must check if the ";" is inside parenthesis - if so, it doesn't count (e.g. "for(;;)") //only when the number of "(" is the same as the number of ")", the ";" is outside string sCheck = sLine.Replace("(", ""); int nNumRight = sLine.Length-sCheck.Length; sCheck = sLine.Replace(")", ""); int nNumLeft = sLine.Length-sCheck.Length; if (nNumRight != nNumLeft) continue; } sScript = sScript.Remove(0, sLine.Length); sLine = sLine.Remove(sLine.Length-1,1); break; } sLine = sLine.Trim(); //handle if the line only consists of a { or } if (sLine.Length == 0) { if (HandleNodeBorderChars(sDividerChar, ref currentNode)) continue; } //empty and remmed lines are ignored: if (sLine.Length == 0 || sLine.IndexOf("//") == 0) { continue; } if (currentNode.GetType() == typeof(ClassNode)) //.Depth == 1) //class level, i.e. where methods are defined { //search for "on method([args])" Match m = Regex.Match(sLine, "on\\s*\\w*\\s*[(][^()]*[)]"); if (m.Success) { string sMethod = m.Value.Replace("on ", "").Trim(); string sArgs = sMethod.Remove(0,sMethod.IndexOf("(")); sMethod = sMethod.Substring(0,sMethod.IndexOf("(")); MethodNode methodNode = new MethodNode(); methodNode.DefineArguments(sArgs.Substring(1,sArgs.Length-2)); currentNode.AppendChild(sMethod, methodNode); currentNode = methodNode; continue; } } //separate code flow keywords/tokens from expressions if (sLine.IndexOf(":") == sLine.Length-1) { //it's a label. Labels can currently only occur on Method level if (currentNode.GetType() != typeof(MethodNode)) throw new Exception("Labels must be defined in Method scope!"); //TODO: Labels can't be nodes - they're not defined with {}'s... More like an HTML anchor //sLine.Substring(0,sLine.Length-2) } #region Check for keywords foreach (string sKeyword in aKeywords) { //[^\\w]+*[( ]* Match m = Regex.Match(sLine+" ", sKeyword+"[^\\w]+[( ]*"); //"\\s*[(]*"); if (m.Success) { ChunkNode newNode = null; string sArgs = GetStringWithinParenthesis(sLine); switch (sKeyword) { case "for": ForNode forNode = new ForNode(); forNode.SetConditions(sArgs); newNode = forNode; //With the current line seek method, the ";" in for(;;) forces us to look ahead in script //TODO: lookahead for(;;) break; case "if": if (sArgs == null) throw new Exception("If statement incomplete"); IfNode ifNode = new IfNode(); ifNode.SetIfStatement(sArgs); newNode = ifNode; break; case "else if": case "else": //is the current node an IfNode? if (currentNode.GetType() != typeof(IfNode)) throw new Exception("\""+sKeyword+"\" must come after an \"if\" statement"); IfNode elseifNode = new IfNode(); if (sKeyword == "else if") { //TODO: don't understand C# scopes... Why can't I define sArgs here too? Can't see any risk for confusion or mistakes!? //And sometimes it's too slack: //a member variable can have the same name as a variable in a method with no complaits, //although that is clearly a mistake in most cases? if (sArgs == null) throw new Exception("Else if statement incomplete"); elseifNode.SetIfStatement(sArgs); } IfNode oldIfNode = (IfNode)currentNode; oldIfNode.SetNextIfNode(elseifNode); newNode = elseifNode; break; } if (newNode!=null) { newNode.CloseNodeAfterNextLine = true; currentNode.AppendChild(sKeyword, newNode); currentNode = newNode; } break; } } #endregion if (HandleNodeBorderChars(sDividerChar, ref currentNode)) continue; string sStatement = sLine; ExpressionNode expNode = new ExpressionNode(); expNode.SetExpression(sStatement); currentNode.AppendChild(sStatement, expNode); //TODO: how to check nicely if ChunkNode is one of the base classes of currentNode?? This is ugly (?): try { ChunkNode chunkNode = (ChunkNode)currentNode; if (chunkNode.CloseNodeAfterNextLine) currentNode = (BaseNode)currentNode.ParentNode; } catch {} } // System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); // rootNode.AddToXml(doc); // doc.Save("Testing.xml"); return classNode; }
//returns false when finished public bool Step() { bool bDebug = false; BaseNode owningNode = (BaseNode)this.m_callStack.Peek(); BaseNode nextNode = owningNode.GetNextNode(this, this.m_currentNode, null); if (nextNode == null) { if (bDebug) EH.Put("No more nodes on that depth"); //that node is finished. Go up one level or quit! if (this.m_callStack.Count <= 1) //there has to be two nodes above the current! { //fire event! Quit! return false; } //step up one level, and find next node there: this.m_currentNode = (BaseNode)this.m_callStack.Pop(); this.Step(); } else { if (nextNode.ParentNode != owningNode) //when going down one level (always just one) { this.m_callStack.Push(nextNode.ParentNode); this.m_currentNode = nextNode; if (bDebug) EH.Put("Entering childnode: "+nextNode.Name); } else //new node is at same level { this.m_currentNode = nextNode; if (bDebug) EH.Put("Nextsibling : "+nextNode.Name); //nextNode.GetType().ToString() } } // if (this.m_currentNode.GetType() == typeof(IfNode)) // this.m_currentNode = this.m_currentNode; //only ExpressionNodes can be executed, the others are only asked for next node. if (this.m_currentNode.GetType() != typeof(ExpressionNode)) { this.m_callStack.Push(this.m_currentNode); this.m_currentNode = null; return this.Step(); } else { this.m_currentNode.Execute(this); //object oVal = return true; } }