static int Main(string[] args) { string source = ""; string target = ""; string filename = ""; bool addFunctions = false; if (args.Length < 2) { Console.WriteLine("SucCompiler by sucklead (http://dcotetools.sucklead.com/p/succompiler.html)"); Console.WriteLine("Version [{0}]", Assembly.GetExecutingAssembly().GetName().Version); Console.WriteLine(); Console.WriteLine("To compile a single file"); Console.WriteLine("SucCompiler {source directory} {binary directory} {source filename}"); Console.WriteLine(@"e.g. To compile src\gamescripts\01_house\$debug\debugblack.hfs into directory bin"); Console.WriteLine("from directory scripts:"); Console.WriteLine(@"SucCompiler src bin gamescripts\01_house\$debug\debugblack.hfs"); Console.WriteLine(); Console.WriteLine("To compile all file in a directory"); Console.WriteLine("SucCompiler {source directory} {binary directory}"); Console.WriteLine("e.g. to compile everything in src to bin"); Console.WriteLine("from directory scripts:"); Console.WriteLine("SucCompiler src bin"); Console.WriteLine(); Console.WriteLine("Easiest way to run it is from within the Scripts directory:"); Console.WriteLine("SucCompiler src newbin"); return(-1); } //set source and target source = args[0].Replace("/", "\\"); target = args[1].Replace("/", "\\");; Console.WriteLine("SucCompiler by sucklead started at {0}", DateTime.Now); Console.WriteLine("Version [{0}]", Assembly.GetExecutingAssembly().GetName().Version); Console.WriteLine("Source -> {0}", source); Console.WriteLine("Target -> {0}", target); //addfunctions parameter? //if (args.Length > 3) //{ // if (bool.TryParse(args[1], out addFunctions)) // { // addFunctions = false; // } //} ////debug a script? //if (Debugger.IsAttached) //{ // Directory.SetCurrentDirectory(@"F:\Games\Call Of Cthulhu DCoTE\Scripts"); // filename = @"gamescripts\06_refinery\animatedreachtargets\goldvault\goldvaultsouthvalveturn.bin"; // //addFunctions = true; //} FunctionTable.LoadData(); //set the options Compiler compiler = new Compiler(); compiler.AddFunctions = addFunctions; compiler.SourceDirectory = source; compiler.TargetDirectory = target; if (args.Length > 2) { for (int a = 2; a < args.Length; a++) { filename = args[a].Replace("/", "\\");; if (filename.StartsWith(source)) { filename = filename.Substring(source.Length + 1); } //convert to windows if (File.Exists(Path.Combine(source, filename))) { compiler.CompileFile(filename); } else { Console.WriteLine("ERROR: Compile source {0} does not exist", Path.Combine(source, filename)); return(-2); } } } else { filename = ""; if (Directory.Exists(source)) { compiler.CompileDirectory(source); } else { Console.WriteLine("ERROR: Compile source {0} does not exist", source); return(-3); } } //save function table if anything has changed FunctionTable.SaveData(); Console.WriteLine("Compile completed at {0}.", DateTime.Now); //Console.WriteLine("\n\nPress <Enter> to exit.."); //Console.ReadLine(); return(0); }
private void CompileNode(SyntaxNode node) { //if (node is GlobalStatementSyntax) //{ //GlobalStatementSyntax globalStatement = node as GlobalStatementSyntax; if (node is GlobalStatementSyntax) { node = ((GlobalStatementSyntax)node).Statement; } if (node is BlockSyntax) { BlockSyntax block = node as BlockSyntax; foreach (StatementSyntax statement in block.Statements) { CompileNode(statement); } } else if (node is ParenthesizedExpressionSyntax) { ParenthesizedExpressionSyntax parenthesizedExpression = node as ParenthesizedExpressionSyntax; CompileNode(parenthesizedExpression.Expression); if (node.Parent.Kind() == SyntaxKind.LogicalNotExpression || // TODO - check this still works node.Parent.Kind() == SyntaxKind.BitwiseNotExpression || node.Parent.Kind() == SyntaxKind.UnaryMinusExpression) { OP_NEG opNeg = new OP_NEG(); OpCodes.Add(opNeg); } } else if (node is ExpressionStatementSyntax) { ExpressionStatementSyntax expressionStatement = node as ExpressionStatementSyntax; CompileNode(expressionStatement.Expression); } else if (node is LiteralExpressionSyntax) { LiteralExpressionSyntax literalExpression = node as LiteralExpressionSyntax; OP_PUSH opPush = new OP_PUSH(); opPush.DataIndex = Literals[literalExpression].Address; OpCodes.Add(opPush); if (Literals[literalExpression].IsNegative) { //push a negative on top OP_NEG opNeg = new OP_NEG(); OpCodes.Add(opNeg); } } //else if (node is null) //{ //} else if (node is PrefixUnaryExpressionSyntax) { PrefixUnaryExpressionSyntax prefixUnaryExpression = node as PrefixUnaryExpressionSyntax; //a not? negatives are handled later if (prefixUnaryExpression.Kind() == SyntaxKind.LogicalNotExpression) { CompileNode(prefixUnaryExpression.Operand); //add a not OP_NOT opNot = new OP_NOT(); OpCodes.Add(opNot); } else { CompileNode(prefixUnaryExpression.Operand); } } else if (node is IdentifierNameSyntax) { IdentifierNameSyntax identifierName = node as IdentifierNameSyntax; OP_PUSH opPush = new OP_PUSH(); if (identifierName != null) { opPush.DataIndex = Variables[identifierName.ToString()].Address; // TODO check this .PlainName } OpCodes.Add(opPush); if (node.Parent.Kind() == SyntaxKind.UnaryMinusExpression) // TODO - check this { //add a not OP_NEG opNeg = new OP_NEG(); OpCodes.Add(opNeg); } } else if (node is ArgumentSyntax) { ArgumentSyntax argument = node as ArgumentSyntax; if (argument.Expression is PrefixUnaryExpressionSyntax) { //for a negative parse the operand PrefixUnaryExpressionSyntax prefixUnaryExpression = argument.Expression as PrefixUnaryExpressionSyntax; CompileNode(prefixUnaryExpression.Operand); } //if (argument.Expression is LiteralExpressionSyntax // || argument.Expression is IdentifierNameSyntax) else { CompileNode(argument.Expression); } } //a function invocation else if (node is InvocationExpressionSyntax) { InvocationExpressionSyntax invocationExpressionSyntax = node as InvocationExpressionSyntax; //first we have an identifier expression IdentifierNameSyntax identifierNameSyntax = invocationExpressionSyntax.Expression as IdentifierNameSyntax; //then arguments foreach (ArgumentSyntax argumentSyntax in invocationExpressionSyntax.ArgumentList.Arguments) //TODO .Reverse()? { //Console.WriteLine(" [Literal]"); //Console.WriteLine(" " + (LiteralExpressionSyntax)(argumentSyntax.Expression)); CompileNode(argumentSyntax); } if (identifierNameSyntax.ToString() == "Print") { OP_PRINT opPrint = new OP_PRINT(); OpCodes.Add(opPrint); } else { //push the function code OP_PUSH opPush = new OP_PUSH(); if (!FunctionTable.Functions.ContainsKey(identifierNameSyntax.ToString())) { if (!this.AddFunctions && !this.justPatchFunctions) { hasMissingFunctions = true; //if (!this.DirectoryBased) if (true) { Console.WriteLine(string.Format("Missing function {0}", identifierNameSyntax.ToString())); } opPush.DataIndex = 0x0FF0; } else { Console.WriteLine(string.Format("Fetching function {0}", identifierNameSyntax.ToString())); short functionPointer = FunctionTable.FindFunction(this.ScriptFilename.Replace(".hfs", ".bin"), identifierNameSyntax.ToString(), opPush.Address + 1); opPush.DataIndex = functionPointer; } } else { opPush.DataIndex = FunctionTable.Functions[identifierNameSyntax.ToString()]; } OpCodes.Add(opPush); //add function call OP_FUNCTION opFunction = new OP_FUNCTION(); OpCodes.Add(opFunction); //do a discard if (node.Parent is BinaryExpressionSyntax || node.Parent is AssignmentExpressionSyntax) { } else { OP_DISCARD opDiscard = new OP_DISCARD(); OpCodes.Add(opDiscard); } } } else if (node is AssignmentExpressionSyntax) { AssignmentExpressionSyntax assignmentExpression = node as AssignmentExpressionSyntax; CompileNode(assignmentExpression.Right); IdentifierNameSyntax identifierName = assignmentExpression.Left as IdentifierNameSyntax; //gettop the left OP_GETTOP opGettop = new OP_GETTOP(); opGettop.DataIndex = Variables[identifierName.ToString()].Address; OpCodes.Add(opGettop); //for an if we need to keep the value //or for a double assign if (assignmentExpression.Parent.Kind() != SyntaxKind.IfStatement && assignmentExpression.Parent.Kind() != SyntaxKind.SimpleAssignmentExpression) { //do a discard OP_DISCARD opDiscard = new OP_DISCARD(); OpCodes.Add(opDiscard); } } else if (node is BinaryExpressionSyntax) { BinaryExpressionSyntax binaryExpression = node as BinaryExpressionSyntax; if (binaryExpression.OperatorToken.Kind() == SyntaxKind.EqualsToken) { CompileNode(binaryExpression.Right); IdentifierNameSyntax identifierName = binaryExpression.Left as IdentifierNameSyntax; //gettop the left OP_GETTOP opGettop = new OP_GETTOP(); opGettop.DataIndex = Variables[identifierName.ToString()].Address; OpCodes.Add(opGettop); //for an if we need to keep the value if (binaryExpression.Parent.Kind() != SyntaxKind.IfStatement) { //do a discard OP_DISCARD opDiscard = new OP_DISCARD(); OpCodes.Add(opDiscard); } } else if (binaryExpression.OperatorToken.Kind() == SyntaxKind.EqualsEqualsToken) { CompileNode(binaryExpression.Left); CompileNode(binaryExpression.Right); OP_EQUAL opEqual = new OP_EQUAL(); OpCodes.Add(opEqual); if (node.Parent.Kind() == SyntaxKind.ExpressionStatement) { //just discard the result OP_DISCARD opDiscard = new OP_DISCARD(); OpCodes.Add(opDiscard); } } else if (binaryExpression.OperatorToken.Kind() == SyntaxKind.ExclamationEqualsToken) { CompileNode(binaryExpression.Left); CompileNode(binaryExpression.Right); OP_NOT_EQUAL opNotEqual = new OP_NOT_EQUAL(); OpCodes.Add(opNotEqual); } else if (binaryExpression.OperatorToken.Kind() == SyntaxKind.MinusToken) { CompileNode(binaryExpression.Left); CompileNode(binaryExpression.Right); OP_MINUS opEqual = new OP_MINUS(); OpCodes.Add(opEqual); } else if (binaryExpression.OperatorToken.Kind() == SyntaxKind.PlusToken) { CompileNode(binaryExpression.Left); CompileNode(binaryExpression.Right); OP_CONCAT opEqual = new OP_CONCAT(); OpCodes.Add(opEqual); } else if (binaryExpression.OperatorToken.Kind() == SyntaxKind.GreaterThanToken) { CompileNode(binaryExpression.Left); CompileNode(binaryExpression.Right); OP_MORE_THAN opEqual = new OP_MORE_THAN(); OpCodes.Add(opEqual); } else if (binaryExpression.OperatorToken.Kind() == SyntaxKind.LessThanToken) { CompileNode(binaryExpression.Left); CompileNode(binaryExpression.Right); OP_LESS_THAN opEqual = new OP_LESS_THAN(); OpCodes.Add(opEqual); } else if (binaryExpression.OperatorToken.Kind() == SyntaxKind.LessThanEqualsToken) { CompileNode(binaryExpression.Left); CompileNode(binaryExpression.Right); OP_LESS_THAN_OR_EQUAL opLessOrEqual = new OP_LESS_THAN_OR_EQUAL(); OpCodes.Add(opLessOrEqual); } else if (binaryExpression.OperatorToken.Kind() == SyntaxKind.GreaterThanEqualsToken) { CompileNode(binaryExpression.Left); CompileNode(binaryExpression.Right); OP_MORE_THAN_OR_EQUAL opGreatOrEqual = new OP_MORE_THAN_OR_EQUAL(); OpCodes.Add(opGreatOrEqual); } else if (binaryExpression.OperatorToken.Kind() == SyntaxKind.BarBarToken) { CompileNode(binaryExpression.Left); CompileNode(binaryExpression.Right); OP_OR opOr = new OP_OR(); OpCodes.Add(opOr); } else if (binaryExpression.OperatorToken.Kind() == SyntaxKind.AmpersandAmpersandToken) { CompileNode(binaryExpression.Left); CompileNode(binaryExpression.Right); OP_AND opAnd = new OP_AND(); OpCodes.Add(opAnd); } else if (binaryExpression.OperatorToken.Kind() == SyntaxKind.AsteriskToken) { CompileNode(binaryExpression.Left); CompileNode(binaryExpression.Right); OP_MULTIPLY opMultiply = new OP_MULTIPLY(); OpCodes.Add(opMultiply); } else if (binaryExpression.OperatorToken.Kind() == SyntaxKind.SlashToken) { CompileNode(binaryExpression.Left); CompileNode(binaryExpression.Right); OP_DIVIDE opDivide = new OP_DIVIDE(); OpCodes.Add(opDivide); } } else if (node is WhileStatementSyntax) { WhileStatementSyntax whileStatement = node as WhileStatementSyntax; short whileAddress = OpCode.NextAddress; CompileNode(whileStatement.Condition); //look at the condition here OP_JMPF opJmpF = new OP_JMPF(); OpCodes.Add(opJmpF); CompileNode(whileStatement.Statement); //jmp back to the condition OP_JMP opJmp = new OP_JMP(); opJmp.DataIndex = whileAddress; OpCodes.Add(opJmp); //jump over the jmp back opJmpF.DataIndex = (short)(opJmp.Address + 3); } else if (node is IfStatementSyntax) { IfStatementSyntax ifStatement = node as IfStatementSyntax; //look at the condition here CompileNode(ifStatement.Condition); short ifAddress = OpCode.NextAddress; //do a jump to end if condition is false OP_JMPF opJmpF = new OP_JMPF(); OpCodes.Add(opJmpF); CompileNode(ifStatement.Statement); //has an else option? if (ifStatement.Else != null) //TODO - check this works { OP_JMP opJmp = new OP_JMP(); OpCodes.Add(opJmp); //save this as the else jump so we can hook it up later this.ElseJmps.Push(opJmp); } //add in the jump target JUMPTARGET jumpTarget = new JUMPTARGET(); jumpTarget.DataIndex = ifAddress; OpCodes.Add(jumpTarget); //jump is to here opJmpF.DataIndex = jumpTarget.Address; CompileNode(ifStatement.Else); } else if (node is ElseClauseSyntax) { ElseClauseSyntax elseClause = node as ElseClauseSyntax; CompileNode(elseClause.Statement); //pop off last one OP_JMP opJmp = this.ElseJmps.Pop(); //add in the jump target JUMPTARGET jumpTarget = new JUMPTARGET(); jumpTarget.DataIndex = opJmp.Address; OpCodes.Add(jumpTarget); //jump is to here opJmp.DataIndex = jumpTarget.Address; } //} //else if (node is BlockSyntax) //{ // BlockSyntax block = node as BlockSyntax; // foreach (StatementSyntax statement in block.Statements) // { // CompileNode(statement); // } //} }