public override bool Equals(object obj) { ArrayVarType v2 = (obj as ArrayVarType); if (v2 == null) { return(false); } return(baseType.Equals(v2.baseType) && this.arrayDimensions.SequenceEqual(v2.arrayDimensions)); }
/// <summary> /// array-access -> ID LB expr-list RB /// </summary> /// <param name="vinfo"></param> /// <param name="exprListNode"></param> private void putArrayAddressInRcx(VarInfo vinfo, TreeNode exprListNode) { ArrayVarType typ = vinfo.VType as ArrayVarType; if (typ == null) { throw new Exception("ICE!!! Arraytype cannot be null or typ not Array type!! tpy: " + typ == null ? "null" : typ.typeString); } List <VarType> types; exprlistNodeCode(exprListNode.Children[2], out types); //expr-list -> expr expr-list' if (types.Count != typ.arrayDimensions.Count) { throw new Exception("Error!! Arrays dimension mismatch!!"); } foreach (var t in types) { if (t != VarType.NUMBER) { throw new Exception("Error!! only numbers are valid as array indices!! type: " + t.typeString); } } emit("mov rcx, 0"); for (int i = 0; i < typ.arrayDimensions.Count; i++) { int product = 1; for (int j = i + 1; j < typ.arrayDimensions.Count; j++) { product *= typ.arrayDimensions[j]; } emit("pop rax"); //get next from expr-list emit("movq xmm0, rax"); //convert to double emit("cvtsd2si rax, xmm0"); //convert to int emit("imul rax, rax,{0}", product); //dest, op1, op2 emit("add rcx, rax"); } if (vinfo.isGlobal) { emit("shl rcx, 3"); //same as imul rcx, 8 but faster emit("add rcx, {0}", vinfo.Label); } else { emit("lea rcx, [rcx*8+{0}]", vinfo.Label); } }
static void typeNodeCode(TreeNode n, out VarType type) { VarType t1; var nonArrayTypeNode = n.Children[0]; var n2 = nonArrayTypeNode.Children[0]; switch (n2.Symbol) { case "NUMBER": t1 = VarType.NUMBER; break; case "STRING": t1 = VarType.STRING; break; case "VOID": t1 = VarType.VOID; break; default: throw new Exception("Internal Compiler Error."); } if (n.Children.Count == 1) { type = t1; } else { List <int> dims; numlistNodeCode(n.Children[2], out dims); foreach (int i in dims) { if (i < 0) { break; } } type = new ArrayVarType(t1, dims); } }
/// <summary> /// type -> non-array-type | non-array-type LB num-list RB /// </summary> /// <param name="n"></param> /// <param name="type"></param> private void typeNodeCode(TreeNode n, out VarType type) { VarType t1; nonarraytypeNodeCode(n.Children[0], out t1); //Get type if (n.Children.Count == 4) { List <int> dims; numlistNodeCode(n.Children[2], out dims); foreach (var i in dims) { if (i < 0) { throw new Exception("Error!! Value is not positive!! i: " + i.ToString()); } } type = new ArrayVarType(t1, dims); } else { type = t1; } }
static void putArrayAddressInRcx(VarInfo vinfo, TreeNode n) { bool isPointer = false; ArrayVarType typ = vinfo.VType as ArrayVarType; if (typ == null) { typ = (vinfo.VType as PointerVarType).pointedToType as ArrayVarType; isPointer = true; if (typ == null) { throw new Exception("Internal Compiler Error."); } } List <VarType> types; exprlistNodeCode(n, out types); if (types.Count != typ.arrayDimensions.Count) { throw new Exception("Array dimension mismatch."); } foreach (var t in types) { if (t != VarType.NUMBER) { throw new Exception("Only numbers can be array indices."); } } emit("mov rcx,0"); for (int i = 0; i < typ.arrayDimensions.Count; ++i) { int product = 1; for (int j = i + 1; j < typ.arrayDimensions.Count; ++j) { product *= typ.arrayDimensions[j]; } emit("pop rax"); emit("movq xmm0,rax"); emit("cvtsd2si rax,xmm0"); var abortlbl = label(); var resumelbl = label(); emit("mov rdx,{0}", typ.arrayDimensions[i]); emit("cmp rax,rdx"); emit("jge {0}", abortlbl); emit("cmp rax,0"); emit("jl {0}", abortlbl); emit("jmp {0}", resumelbl); emit("{0}:", abortlbl); emit("call abort"); emit("{0}:", resumelbl); emit("imul rax,rax,{0}", product); emit("add rcx,rax"); } if (vinfo.isGlobal) { emit("imul rcx,8"); emit("add rcx,{0}", vinfo.Label); } else { if (isPointer) { emit("mov rax,[{0}]", vinfo.Label); emit("lea rcx, [rcx*8+rax]"); } else { emit("lea rcx,[rcx*8+{0}]", vinfo.Label); } } }
/// <summary> /// factor -> NUM | LP expr RP | STRING-CONSTANT | ID | func-call /// </summary> /// <param name="n"></param> /// <param name="type"></param> private void factorNodeCode(TreeNode n, out VarType type) { var child = n.Children[0]; switch (child.Symbol) { case "NUM": makeDouble_and_push(child.Token.Lexeme); type = VarType.NUMBER; break; case "LP": exprNodeCode(n.Children[1], out type); break; case "STRING-CONSTANT": //Stores the address of the string data on stack string lbl; stringconstantNodeCode(child, out lbl); emit("mov rax, {0}", lbl); emit("push rax"); type = VarType.STRING; break; case "ID": string vname = n.Children[0].Token.Lexeme; if (!symtable.ContainsInCurrentScopes(vname)) { symtable.printScopes(); throw new Exception("ERROR!!! Undeclared Variable: " + vname); } VarInfo vi = symtable[vname]; ArrayVarType atyp = vi.VType as ArrayVarType; if (vi.VType == VarType.NUMBER || vi.VType == VarType.STRING || atyp != null) { emit("mov rax,[{0}]", symtable[vname].Label); emit("push rax"); type = vi.VType; } else { throw new Exception("ICE!!! Expected type NUMBER, STRING, or ARRAY. Recieved: " + vi.VType); } break; case "func-call": funccallNodeCode(child, out type); if (type == VarType.VOID) { throw new Exception("ICE!!! Can't use VOID in math expressions"); } emit("push rax"); break; case "array-access": vname = child.Children[0].Token.Lexeme; var vinfo = symtable[vname]; if (vinfo == null) { throw new Exception("Error!!! Trying to access undeclared variable: " + vname); } putArrayAddressInRcx(vinfo, n.Children[0]); emit("mov rax, [rcx]"); emit("push rax"); type = (vinfo.VType as ArrayVarType).baseType; break; default: throw new Exception("ICE!!! Expected NUM, LP, STRING-CONSTANT, or ID Recieved:" + child.Symbol); } }