From 382fb8cea6c7a71ecbdab2a4ef8526bf3045fb2e Mon Sep 17 00:00:00 2001 From: Johan Berntsson Date: Fri, 4 Jul 2008 08:59:41 +0000 Subject: The new llScript-cs parser. Thanks Mike --- .../DotNetEngine/Compiler/LSL/CSCodeGenerator.cs | 775 +++++++++++++++++++++ 1 file changed, 775 insertions(+) create mode 100644 OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/CSCodeGenerator.cs (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/CSCodeGenerator.cs') diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/CSCodeGenerator.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/CSCodeGenerator.cs new file mode 100644 index 0000000..142e791 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/CSCodeGenerator.cs @@ -0,0 +1,775 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Collections.Generic; +using Tools; + +namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL +{ + public class CSCodeGenerator + { + private SYMBOL m_astRoot = null; + private int m_braceCount; // for indentation + + /// + /// Pass the new CodeGenerator a string containing the LSL source. + /// + /// String containing LSL source. + public CSCodeGenerator(string script) + { + Parser p = new LSLSyntax(); + // Obviously this needs to be in a try/except block. + LSL2CSCodeTransformer codeTransformer = new LSL2CSCodeTransformer(p.Parse(script)); + m_astRoot = codeTransformer.Transform(); + } + + /// + /// Pass the new CodeGenerator an abstract syntax tree. + /// + /// The root node of the AST. + public CSCodeGenerator(SYMBOL astRoot) + { + m_braceCount = 0; + m_astRoot = astRoot; + } + + /// + /// Generate the code from the AST we have. + /// + /// String containing the generated C# code. + public string Generate() + { + string retstr = String.Empty; + + // standard preamble + //retstr = "using OpenSim.Region.ScriptEngine.Common;\n"; + //retstr += "using System.Collections.Generic;\n\n"; + //retstr += "namespace SecondLife\n"; + //retstr += "{\n"; + //retstr += " public class Script : OpenSim.Region.ScriptEngine.Common\n"; + //retstr += " {\n"; + + // here's the payload + m_braceCount += 2; + retstr += "\n"; + foreach (SYMBOL s in m_astRoot.kids) + retstr += GenerateNode(s); + + // close braces! + //retstr += " }\n"; + //retstr += "}\n"; + m_braceCount -= 2; + + return retstr; + } + + /// + /// Recursively called to generate each type of node. Will generate this + /// node, then all it's children. + /// + /// The current node to generate code for. + /// String containing C# code for SYMBOL s. + private string GenerateNode(SYMBOL s) + { + string retstr = String.Empty; + + // make sure to put type lower in the inheritance hierarchy first + // ie: since IdentArgument and ExpressionArgument inherit from + // Argument, put IdentArgument and ExpressionArgument before Argument + if (s is GlobalFunctionDefinition) + retstr += GenerateGlobalFunctionDefinition((GlobalFunctionDefinition) s); + else if (s is GlobalVariableDeclaration) + retstr += GenerateGlobalVariableDeclaration((GlobalVariableDeclaration) s); + else if (s is State) + retstr += GenerateState((State) s); + else if (s is CompoundStatement) + retstr += GenerateCompoundStatement((CompoundStatement) s); + else if (s is Declaration) + retstr += GenerateDeclaration((Declaration) s); + else if (s is Statement) + retstr += GenerateStatement((Statement) s); + else if (s is ReturnStatement) + retstr += GenerateReturnStatement((ReturnStatement) s); + else if (s is StateChange) + retstr += GenerateStateChange((StateChange) s); + else if (s is IfStatement) + retstr += GenerateIfStatement((IfStatement) s); + else if (s is WhileStatement) + retstr += GenerateWhileStatement((WhileStatement) s); + else if (s is DoWhileStatement) + retstr += GenerateDoWhileStatement((DoWhileStatement) s); + else if (s is ForLoop) + retstr += GenerateForLoop((ForLoop) s); + else if (s is ArgumentList) + retstr += GenerateArgumentList((ArgumentList) s); + else if (s is Assignment) + retstr += GenerateAssignment((Assignment) s); + else if (s is BinaryExpression) + retstr += GenerateBinaryExpression((BinaryExpression) s); + else if (s is ParenthesisExpression) + retstr += GenerateParenthesisExpression((ParenthesisExpression) s); + else if (s is UnaryExpression) + retstr += GenerateUnaryExpression((UnaryExpression) s); + else if (s is IncrementDecrementExpression) + retstr += GenerateIncrementDecrementExpression((IncrementDecrementExpression) s); + else if (s is TypecastExpression) + retstr += GenerateTypecastExpression((TypecastExpression) s); + else if (s is FunctionCall) + retstr += GenerateFunctionCall((FunctionCall) s); + else if (s is VectorConstant) + retstr += GenerateVectorConstant((VectorConstant) s); + else if (s is RotationConstant) + retstr += GenerateRotationConstant((RotationConstant) s); + else if (s is ListConstant) + retstr += GenerateListConstant((ListConstant) s); + else if (s is Constant) + retstr += GenerateConstant((Constant) s); + else if (s is IdentDotExpression) + retstr += ((IdentDotExpression) s).Name + "." + ((IdentDotExpression) s).Member; + else if (s is IdentExpression) + retstr += ((IdentExpression) s).Name; + else if (s is IDENT) + retstr += ((TOKEN) s).yytext; + else + { + foreach (SYMBOL kid in s.kids) + retstr += GenerateNode(kid); + } + + return retstr; + } + + /// + /// Generates the code for a GlobalFunctionDefinition node. + /// + /// The GlobalFunctionDefinition node. + /// String containing C# code for GlobalFunctionDefinition gf. + private string GenerateGlobalFunctionDefinition(GlobalFunctionDefinition gf) + { + string retstr = String.Empty; + + // we need to separate the argument declaration list from other kids + List argumentDeclarationListKids = new List(); + List remainingKids = new List(); + + foreach (SYMBOL kid in gf.kids) + if (kid is ArgumentDeclarationList) + argumentDeclarationListKids.Add(kid); + else + remainingKids.Add(kid); + + retstr += WriteIndented(String.Format("{0} {1}(", gf.ReturnType, gf.Name)); + + // print the state arguments, if any + foreach (SYMBOL kid in argumentDeclarationListKids) + retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid); + + retstr += ")\n"; + + foreach (SYMBOL kid in remainingKids) + retstr += GenerateNode(kid); + + return retstr; + } + + /// + /// Generates the code for a GlobalVariableDeclaration node. + /// + /// The GlobalVariableDeclaration node. + /// String containing C# code for GlobalVariableDeclaration gv. + private string GenerateGlobalVariableDeclaration(GlobalVariableDeclaration gv) + { + string retstr = String.Empty; + + foreach (SYMBOL s in gv.kids) + { + retstr += Indent(); + retstr += GenerateNode(s); + retstr += ";\n"; + } + + return retstr; + } + + /// + /// Generates the code for a State node. + /// + /// The State node. + /// String containing C# code for State s. + private string GenerateState(State s) + { + string retstr = String.Empty; + + foreach (SYMBOL kid in s.kids) + if (kid is StateEvent) + retstr += GenerateStateEvent((StateEvent) kid, s.Name); + else + retstr += String.Format("ERROR: State '{0}' contains a '{1}\n", s.Name, kid.GetType()); + + return retstr; + } + + /// + /// Generates the code for a StateEvent node. + /// + /// The StateEvent node. + /// The name of the parent state. + /// String containing C# code for StateEvent se. + private string GenerateStateEvent(StateEvent se, string parentStateName) + { + string retstr = String.Empty; + + // we need to separate the argument declaration list from other kids + List argumentDeclarationListKids = new List(); + List remainingKids = new List(); + + foreach (SYMBOL kid in se.kids) + if (kid is ArgumentDeclarationList) + argumentDeclarationListKids.Add(kid); + else + remainingKids.Add(kid); + + // "state" (function) declaration + retstr += WriteIndented(String.Format("public void {0}_event_{1}(", parentStateName, se.Name)); + + // print the state arguments, if any + foreach (SYMBOL kid in argumentDeclarationListKids) + retstr += GenerateArgumentDeclarationList((ArgumentDeclarationList) kid); + + retstr += ")\n"; + + foreach (SYMBOL kid in remainingKids) + retstr += GenerateNode(kid); + + return retstr; + } + + /// + /// Generates the code for an ArgumentDeclarationList node. + /// + /// The ArgumentDeclarationList node. + /// String containing C# code for SYMBOL s. + private string GenerateArgumentDeclarationList(ArgumentDeclarationList adl) + { + string retstr = String.Empty; + + int comma = adl.kids.Count - 1; // tells us whether to print a comma + + foreach (Declaration d in adl.kids) + { + retstr += String.Format("{0} {1}", d.Datatype, d.Id); + if (0 < comma--) + retstr += ", "; + } + + return retstr; + } + + /// + /// Generates the code for an ArgumentList node. + /// + /// The ArgumentList node. + /// String containing C# code for SYMBOL s. + private string GenerateArgumentList(ArgumentList al) + { + string retstr = String.Empty; + + int comma = al.kids.Count - 1; // tells us whether to print a comma + + foreach (SYMBOL s in al.kids) + { + retstr += GenerateNode(s); + if (0 < comma--) + retstr += ", "; + } + + return retstr; + } + + /// + /// Generates the code for a CompoundStatement node. + /// + /// The CompoundStatement node. + /// String containing C# code for SYMBOL s. + private string GenerateCompoundStatement(CompoundStatement cs) + { + string retstr = String.Empty; + + // opening brace + retstr += WriteIndentedLine("{"); + m_braceCount++; + + foreach (SYMBOL kid in cs.kids) + retstr += GenerateNode(kid); + + // closing brace + m_braceCount--; + retstr += WriteIndentedLine("}"); + + return retstr; + } + + /// + /// Generates the code for a Declaration node. + /// + /// The Declaration node. + /// String containing C# code for SYMBOL s. + private string GenerateDeclaration(Declaration d) + { + return String.Format("{0} {1}", d.Datatype, d.Id); + } + + /// + /// Generates the code for a Statement node. + /// + /// The Statement node. + /// String containing C# code for SYMBOL s. + private string GenerateStatement(Statement s) + { + string retstr = String.Empty; + + retstr += Indent(); + + foreach (SYMBOL kid in s.kids) + retstr += GenerateNode(kid); + + retstr += ";\n"; + + return retstr; + } + + /// + /// Generates the code for an Assignment node. + /// + /// The Assignment node. + /// String containing C# code for SYMBOL s. + private string GenerateAssignment(Assignment a) + { + string retstr = String.Empty; + + retstr += GenerateNode((SYMBOL) a.kids.Pop()); + retstr +=String.Format(" {0} ", a.AssignmentType); + foreach (SYMBOL kid in a.kids) + retstr += GenerateNode(kid); + + return retstr; + } + + /// + /// Generates the code for a ReturnStatement node. + /// + /// The ReturnStatement node. + /// String containing C# code for SYMBOL s. + private string GenerateReturnStatement(ReturnStatement rs) + { + string retstr = String.Empty; + + retstr += "return "; + + foreach (SYMBOL kid in rs.kids) + retstr += GenerateNode(kid); + + return retstr; + } + + /// + /// Generates the code for a IfStatement node. + /// + /// The IfStatement node. + /// String containing C# code for SYMBOL s. + private string GenerateIfStatement(IfStatement ifs) + { + string retstr = String.Empty; + + retstr += WriteIndented("if ("); + retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); + retstr += ")\n"; + + // CompoundStatement handles indentation itself but we need to do it + // otherwise. + bool indentHere = ifs.kids.Top is Statement; + if (indentHere) m_braceCount++; + retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); + if (indentHere) m_braceCount--; + + if (0 < ifs.kids.Count) // do it again for an else + { + retstr += WriteIndentedLine("else"); + + indentHere = ifs.kids.Top is Statement; + if (indentHere) m_braceCount++; + retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); + if (indentHere) m_braceCount--; + } + + return retstr; + } + + /// + /// Generates the code for a StateChange node. + /// + /// The StateChange node. + /// String containing C# code for SYMBOL s. + private string GenerateStateChange(StateChange sc) + { + return String.Format("state(\"{0}\")", sc.NewState); + } + + /// + /// Generates the code for a WhileStatement node. + /// + /// The WhileStatement node. + /// String containing C# code for SYMBOL s. + private string GenerateWhileStatement(WhileStatement ws) + { + string retstr = String.Empty; + + retstr += WriteIndented("while ("); + retstr += GenerateNode((SYMBOL) ws.kids.Pop()); + retstr += ")\n"; + + // CompoundStatement handles indentation itself but we need to do it + // otherwise. + bool indentHere = ws.kids.Top is Statement; + if (indentHere) m_braceCount++; + retstr += GenerateNode((SYMBOL) ws.kids.Pop()); + if (indentHere) m_braceCount--; + + return retstr; + } + + /// + /// Generates the code for a DoWhileStatement node. + /// + /// The DoWhileStatement node. + /// String containing C# code for SYMBOL s. + private string GenerateDoWhileStatement(DoWhileStatement dws) + { + string retstr = String.Empty; + + retstr += WriteIndentedLine("do"); + + // CompoundStatement handles indentation itself but we need to do it + // otherwise. + bool indentHere = dws.kids.Top is Statement; + if (indentHere) m_braceCount++; + retstr += GenerateNode((SYMBOL) dws.kids.Pop()); + if (indentHere) m_braceCount--; + + retstr += WriteIndented("while ("); + retstr += GenerateNode((SYMBOL) dws.kids.Pop()); + retstr += ");\n"; + + return retstr; + } + + /// + /// Generates the code for a ForLoop node. + /// + /// The ForLoop node. + /// String containing C# code for SYMBOL s. + private string GenerateForLoop(ForLoop fl) + { + string retstr = String.Empty; + + retstr += WriteIndented("for ("); + + // for ( x = 0 ; x < 10 ; x++ ) + // ^^^^^^^ + retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop()); + retstr += "; "; + // for ( x = 0 ; x < 10 ; x++ ) + // ^^^^^^^^ + retstr += GenerateNode((SYMBOL) fl.kids.Pop()); + retstr += "; "; + // for ( x = 0 ; x < 10 ; x++ ) + // ^^^^^ + retstr += GenerateForLoopStatement((ForLoopStatement) fl.kids.Pop()); + retstr += ")\n"; + + // CompoundStatement handles indentation itself but we need to do it + // otherwise. + bool indentHere = fl.kids.Top is Statement; + if (indentHere) m_braceCount++; + retstr += GenerateNode((SYMBOL) fl.kids.Pop()); + if (indentHere) m_braceCount--; + + return retstr; + } + + /// + /// Generates the code for a ForLoopStatement node. + /// + /// The ForLoopStatement node. + /// String containing C# code for SYMBOL s. + private string GenerateForLoopStatement(ForLoopStatement fls) + { + string retstr = String.Empty; + + int comma = fls.kids.Count - 1; // tells us whether to print a comma + + foreach (SYMBOL s in fls.kids) + { + retstr += GenerateNode(s); + if (0 < comma--) + retstr += ", "; + } + + return retstr; + } + + /// + /// Generates the code for a BinaryExpression node. + /// + /// The BinaryExpression node. + /// String containing C# code for SYMBOL s. + private string GenerateBinaryExpression(BinaryExpression be) + { + string retstr = String.Empty; + + retstr += GenerateNode((SYMBOL) be.kids.Pop()); + retstr += String.Format(" {0} ", be.ExpressionSymbol); + foreach (SYMBOL kid in be.kids) + retstr += GenerateNode(kid); + + return retstr; + } + + /// + /// Generates the code for a UnaryExpression node. + /// + /// The UnaryExpression node. + /// String containing C# code for SYMBOL s. + private string GenerateUnaryExpression(UnaryExpression ue) + { + string retstr = String.Empty; + + retstr += ue.UnarySymbol; + retstr += GenerateNode((SYMBOL) ue.kids.Pop()); + + return retstr; + } + + /// + /// Generates the code for a ParenthesisExpression node. + /// + /// The ParenthesisExpression node. + /// String containing C# code for SYMBOL s. + private string GenerateParenthesisExpression(ParenthesisExpression pe) + { + string retstr = String.Empty; + + retstr += "("; + foreach (SYMBOL kid in pe.kids) + retstr += GenerateNode(kid); + retstr += ")"; + + return retstr; + } + + /// + /// Generates the code for a IncrementDecrementExpression node. + /// + /// The IncrementDecrementExpression node. + /// String containing C# code for SYMBOL s. + private string GenerateIncrementDecrementExpression(IncrementDecrementExpression ide) + { + string retstr = String.Empty; + + if (0 < ide.kids.Count) + { + IdentDotExpression dot = (IdentDotExpression) ide.kids.Top; + retstr += String.Format("{0}", ide.PostOperation ? dot.Name + "." + dot.Member + ide.Operation : ide.Operation + dot.Name + "." + dot.Member); + } + else + retstr += String.Format("{0}", ide.PostOperation ? ide.Name + ide.Operation : ide.Operation + ide.Name); + + return retstr; + } + + /// + /// Generates the code for a TypecastExpression node. + /// + /// The TypecastExpression node. + /// String containing C# code for SYMBOL s. + private string GenerateTypecastExpression(TypecastExpression te) + { + string retstr = String.Empty; + + // we wrap all typecasted statements in parentheses + retstr += String.Format("({0}) (", te.TypecastType); + retstr += GenerateNode((SYMBOL) te.kids.Pop()); + retstr += ")"; + + return retstr; + } + + /// + /// Generates the code for a FunctionCall node. + /// + /// The FunctionCall node. + /// String containing C# code for SYMBOL s. + private string GenerateFunctionCall(FunctionCall fc) + { + string retstr = String.Empty; + + retstr += String.Format("{0}(", fc.Id); + + foreach (SYMBOL kid in fc.kids) + retstr += GenerateNode(kid); + + retstr += ")"; + + return retstr; + } + + /// + /// Generates the code for a Constant node. + /// + /// The Constant node. + /// String containing C# code for SYMBOL s. + private string GenerateConstant(Constant c) + { + string retstr = String.Empty; + + // Supprt LSL's weird acceptance of floats with no trailing digits + // after the period. Turn float x = 10.; into float x = 10.0; + if ("LSL_Types.LSLFloat" == c.Type) + { + int dotIndex = c.Value.IndexOf('.') + 1; + if (0 < dotIndex && (dotIndex == c.Value.Length || !Char.IsDigit(c.Value[dotIndex]))) + c.Value = c.Value.Insert(dotIndex, "0"); + } + + // need to quote strings + if ("LSL_Types.LSLString" == c.Type) + retstr += "\""; + retstr += c.Value; + if ("LSL_Types.LSLString" == c.Type) + retstr += "\""; + + return retstr; + } + + /// + /// Generates the code for a VectorConstant node. + /// + /// The VectorConstant node. + /// String containing C# code for SYMBOL s. + private string GenerateVectorConstant(VectorConstant vc) + { + string retstr = String.Empty; + + retstr += String.Format("new {0}(", vc.Type); + retstr += GenerateNode((SYMBOL) vc.kids.Pop()); + retstr += ", "; + retstr += GenerateNode((SYMBOL) vc.kids.Pop()); + retstr += ", "; + retstr += GenerateNode((SYMBOL) vc.kids.Pop()); + retstr += ")"; + + return retstr; + } + + /// + /// Generates the code for a RotationConstant node. + /// + /// The RotationConstant node. + /// String containing C# code for SYMBOL s. + private string GenerateRotationConstant(RotationConstant rc) + { + string retstr = String.Empty; + + retstr += String.Format("new {0}(", rc.Type); + retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += ", "; + retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += ", "; + retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += ", "; + retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += ")"; + + return retstr; + } + + /// + /// Generates the code for a ListConstant node. + /// + /// The ListConstant node. + /// String containing C# code for SYMBOL s. + private string GenerateListConstant(ListConstant lc) + { + string retstr = String.Empty; + + retstr += String.Format("new {0}(", lc.Type); + + foreach (SYMBOL kid in lc.kids) + retstr += GenerateNode(kid); + + retstr += ")"; + + return retstr; + } + + /// + /// Prints text correctly indented, followed by a newline. + /// + /// String of text to print. + /// String containing C# code for SYMBOL s. + private string WriteIndentedLine(string s) + { + return WriteIndented(s) + "\n"; + } + + /// + /// Prints text correctly indented. + /// + /// String of text to print. + /// String containing C# code for SYMBOL s. + private string WriteIndented(string s) + { + return Indent() + s; + } + + /// + /// Prints correct indentation. + /// + /// String containing C# code for SYMBOL s. + private string Indent() + { + string retstr = String.Empty; + + for (int i = 0; i < m_braceCount; i++) + retstr += " "; + + return retstr; + } + } +} -- cgit v1.1