private int GeneratePrimitive(AstPrimitive ast) { if (primitivesTable == null) { primitivesTable = new Dictionary <Symbol, PrimCodegenItem>(); DefinePrimitiveCodegen("+", GenerateArith2, OpCode.ADD); DefinePrimitiveCodegen("-", GenerateArith2, OpCode.SUB); DefinePrimitiveCodegen("*", GenerateArith2, OpCode.MUL); DefinePrimitiveCodegen("/", GenerateArith2, OpCode.DIV); DefinePrimitiveCodegen("%", GenerateArith2, OpCode.MOD); DefinePrimitiveCodegen("=", GenerateArith2, OpCode.EQ); DefinePrimitiveCodegen(">", GenerateArith2, OpCode.GT); DefinePrimitiveCodegen("<", GenerateArith2, OpCode.LT); DefinePrimitiveCodegen("!=", GenerateArith2, OpCode.NE); DefinePrimitiveCodegen(">=", GenerateArith2, OpCode.GE); DefinePrimitiveCodegen("<=", GenerateArith2, OpCode.LE); DefinePrimitiveCodegen("pow", GenerateArith2, OpCode.POW); DefinePrimitiveCodegen("and", GenerateAndOr, OpCode.AND); DefinePrimitiveCodegen("or", GenerateAndOr, OpCode.OR); DefinePrimitiveCodegen("neg", GenerateArith1, OpCode.NEG); DefinePrimitiveCodegen("not", GenerateArith1, OpCode.NOT); DefinePrimitiveCodegen("len", GenerateArith1, OpCode.LEN); DefinePrimitiveCodegen("concat", GenerateArithX, OpCode.CONCAT); } var sym = ast.Identifier.AsIdentifier(); var prim = primitivesTable[sym]; return(prim.method(ast, prim.opcode)); }
// two arguments primitive. // more that two arguments will be raped to list of primitives // (foo 1 2) public static AST Expand(Syntax stx, Environment env) { var list = stx.AsLinkedList <Value>(); var argc = GetArgsCount(list); AssertArgsMinimum("primitive2", "arity mismatch", 2, argc, list, stx); var set_kwd = list[0].AsSyntax(); var arguments = AstBuilder.ExpandListElements(list, 1, env); if (argc == 2) { return(new AstPrimitive(stx, set_kwd, arguments)); } else { // for expression (+ 1 2 3 4) var args = arguments.DuplicateReverse(0, -1); //< (+ 4 3 2 1) var rightarg = args[0]; //< 4 var skip = 1; foreach (var leftarg in args) //< 3, 2, 1, { if (skip-- > 0) { continue; } var values = ValueLinkedList.FromArguments(leftarg, rightarg); var prim = new AstPrimitive(stx, set_kwd, values); rightarg.Set(prim); } return(rightarg.AsAST()); } }
/// <summary> /// This is the code generator for abstract opcode /// </summary> /// <param name="ast"></param> /// <param name="opcode"></param> /// <returns></returns> internal int GenerateArith2(AstPrimitive ast, OpCode opcode) { var temp = Push(); var args = ast.Arguments; int arg0 = Generate(args[0].AsAST()); int arg1 = Generate(args[1].AsAST()); AddABC(opcode, temp, (byte)arg0, (byte)arg1); SP = temp; return(temp); }
/// <summary> /// This is the code generator for abstract opcode /// </summary> /// <param name="ast"></param> /// <param name="opcode"></param> /// <returns></returns> internal int GenerateArith1(AstPrimitive ast, OpCode opcode) { var result = Push(); var args = ast.Arguments; foreach (var arg in args) { var expres = Generate(arg.AsAST()); AddAB(opcode, result, expres); Pop(); } SP = result; return(result); }
/// <summary> /// This is the code generator for abstract opcode /// </summary> /// <param name="ast"></param> /// <param name="opcode"></param> /// <returns></returns> internal int GenerateArithX(AstPrimitive ast, OpCode opcode) { // R(A) := R(B) .. ... .. R(C) var temp = (short)(SP + 1); var args = ast.Arguments; foreach (var arg in args) { var res = Generate(arg.AsAST()); if (res < SpMin) { /// Case if it is addressed directly to the variable /// MOVE R(A) := R(B) AddAB(OpCode.MOVE, Push(), res); } } AddABC(OpCode.CONCAT, temp, temp, (short)(temp + args.Count - 1)); SP = temp; return(temp); }
/// <summary> /// This is the code generator for abstract opcode /// different with arithmetics is the first expression /// returns true will terminate execution /// </summary> /// <param name="ast"></param> /// <param name="opcode"></param> /// <returns></returns> internal int GenerateAndOr(AstPrimitive ast, OpCode opcode) { var isOrOperation = opcode == OpCode.OR; var expected = isOrOperation ? (short)1 : (short)0; /// This is the arguments list var args = ast.Arguments; /// Here will be jump instruction position for each argument var jumps = new int[args.Count]; /// Put result to this value var result = Push(); for (var i = 0; i < args.Count; i++) { var argpos = Generate(args[i].AsAST()); /// ======================================================= /// if (R(B).AsBool == (bool)C) /// {skip next instruction} /// else /// R(A) = R(B) /// ======================================================= AddABC(OpCode.TESTSET, result, argpos, expected); jumps[i] = AddOpcode(Instruction.Nop); Pop(); } Code.Add(Instruction.MakeAB(OpCode.LOADBOOL, result, isOrOperation ? (short)0 : (short)1)); /// now make all jumps to the var pc = PC; foreach (var jmp in jumps) { Code[jmp] = Instruction.MakeASBX(OpCode.JMP, 0, Jmp(jmp, pc)); } SP = result; return(result); }