/// <summary> /// 生成字节码 /// </summary> /// <param name="root">根表达式</param> /// <param name="identifier">源文件ID</param> /// <returns></returns> public static (byte[] Content, ScriptTranslation DefaultTranslations) Generate(ScopeExpression root, CodeIdentifier identifier) { var context = new ByteCodeGeneratorContext(); // 生成主程序段 Generate(context, root); // 生成各种段 var(code, labels, strings, positions, translations) = context.File.CreateSegments(); context.File.Close(); // 准备目标文件 var targetFile = new ByteCodeWriter(); // 写入文件标志 ("VisualNovelScript Version 1, assembly format"的CRC32) targetFile.DirectWrite(0x963EFE4A); // 写入源文件哈希用于跳过重复编译 targetFile.DirectWrite(identifier.Hash); // 写入各种段 targetFile.DirectWrite(translations.ToByteArray()); targetFile.DirectWrite(strings); targetFile.DirectWrite(labels); targetFile.DirectWrite(positions); targetFile.DirectWrite(code); return(targetFile.CreateMainSegment(), translations); }
private static void Generate(ByteCodeGeneratorContext context, Expression expression, params CompilerFlag[] flags) { switch (expression) { case BinaryExpression binaryExpression: Generate(context, binaryExpression.Right); switch (binaryExpression.Operator) { case OperatorType.AddBy: Generate(context, binaryExpression.Left); context.File.OperationCode(OperationCode.ADD, binaryExpression.Position); break; case OperatorType.MinusBy: Generate(context, binaryExpression.Left); context.File.OperationCode(OperationCode.SUB, binaryExpression.Position); break; case OperatorType.MultiplyBy: Generate(context, binaryExpression.Left); context.File.OperationCode(OperationCode.MUL, binaryExpression.Position); break; case OperatorType.DivideBy: Generate(context, binaryExpression.Left); context.File.OperationCode(OperationCode.DIV, binaryExpression.Position); break; } if (binaryExpression.Operator == OperatorType.EqualsTo || binaryExpression.Operator == OperatorType.AddBy || binaryExpression.Operator == OperatorType.MinusBy || binaryExpression.Operator == OperatorType.MultiplyBy || binaryExpression.Operator == OperatorType.DivideBy) { Generate(context, binaryExpression.Left, CompilerFlag.UseSetLocalVariable); if (!(binaryExpression.Left is VariableExpression) && !(binaryExpression.Left is ConstantExpression)) // 对于所有赋值类语句,如果左侧不是自带赋值指令的变量表达式则补充一个赋值指令来改写内存堆栈值 { context.File.OperationCode(OperationCode.STMEM, binaryExpression.Left.Position); } } else { Generate(context, binaryExpression.Left); switch (binaryExpression.Operator) { case OperatorType.PickChild: context.File.OperationCode(OperationCode.PICK, binaryExpression.Position); break; case OperatorType.Add: context.File.OperationCode(OperationCode.ADD, binaryExpression.Position); break; case OperatorType.Minus: context.File.OperationCode(OperationCode.SUB, binaryExpression.Position); break; case OperatorType.Multiply: context.File.OperationCode(OperationCode.MUL, binaryExpression.Position); break; case OperatorType.Divide: context.File.OperationCode(OperationCode.DIV, binaryExpression.Position); break; case OperatorType.GreaterThan: context.File.OperationCode(OperationCode.CGT, binaryExpression.Position); break; case OperatorType.LesserThan: context.File.OperationCode(OperationCode.CLT, binaryExpression.Position); break; case OperatorType.NotLessThan: context.File.OperationCode(OperationCode.CGE, binaryExpression.Position); break; case OperatorType.NotGreaterThan: context.File.OperationCode(OperationCode.CLE, binaryExpression.Position); break; case OperatorType.LogicEqualsTo: context.File.OperationCode(OperationCode.EQL, binaryExpression.Position); break; case OperatorType.LogicNotEqualsTo: context.File.OperationCode(OperationCode.EQL, binaryExpression.Position); context.File.OperationCode(OperationCode.NOT, binaryExpression.Position); break; } } break; case CallExpression callExpression: foreach (var parameter in callExpression.Parameters) { Generate(context, parameter); } context.File.LoadInteger(callExpression.Parameters.Count, callExpression.Position); Generate(context, callExpression.Target); context.File.Call(callExpression.Position); break; case ConditionExpression conditionExpression: // 协同处理ConditionContentExpression var conditionEndLabel = context.NextLabelId; var conditionNextLabel = context.NextLabelId; foreach (var branch in conditionExpression.Contents) { context.File.CreateLabel(conditionNextLabel); conditionNextLabel = context.NextLabelId; Generate(context, branch.Condition); context.File.OperationCode(OperationCode.BVAL, branch.Position); context.File.OperationCode(OperationCode.BF, branch.Position); context.File.Write7BitEncodedInteger(conditionNextLabel); Generate(context, branch.Body); context.File.OperationCode(OperationCode.BR, branch.Body.Position); context.File.Write7BitEncodedInteger(conditionEndLabel); } context.File.CreateLabel(conditionEndLabel); break; case ConstantExpression constantExpression: var isSetConstant = flags.Any(e => e == CompilerFlag.UseSetLocalVariable); if (constantExpression.Name is StringExpression constantNameExpression && !isSetConstant) { switch (constantNameExpression.Value.ToUpper()) { case "TRUE": context.File.LoadBoolean(true, constantExpression.Position); return; case "FALSE": context.File.LoadBoolean(false, constantExpression.Position); return; case "NULL": context.File.LoadNull(constantExpression.Position); return; default: Generate(context, constantNameExpression); break; } } else { Generate(context, constantExpression.Name); } context.File.OperationCode(isSetConstant ? OperationCode.STCON : OperationCode.LDCON, constantExpression.Position); break;