static public Type TypeOfExpr(ParseTreeNode expr, SymbolTable symbolTable) { if (expr.Term.Name == "stringLiteral") { return(typeof(string)); } if (expr.Term.Name == "number") { if (expr.Token.Value is int) { return(typeof(int)); } else { return(typeof(double)); } } else if (expr.Term.Name == "binExpr") { //Type type1 = TypeOfExpr(expr.ChildNodes[0], symbolTable); //Type type2 = TypeOfExpr(expr.ChildNodes[2], symbolTable); return(TypeOfAny(symbolTable, expr.ChildNodes[0], expr.ChildNodes[2])); //if (type1 == typeof(float) || type2 == typeof(float)) // return typeof(float); //return typeof(int); } else if (expr.Term.Name == "identifier") { string ident = expr.Token.ValueString; return(symbolTable.TypeOfVar(ident)); } else if (expr.Term.Name == "functionCall") { string funcName = expr.ChildNodes[0].Token.ValueString; if (!symbolTable.functionTable.ContainsKey(funcName)) { //it might be an array, so we should check for that if (symbolTable.HasVar(funcName) && symbolTable.TypeOfVar(funcName).IsArray) { //it is an array, so just return the appropriate type for the array return(symbolTable.TypeOfVar(funcName).GetElementType()); } else//nope, throw an error { throw new System.Exception("undeclared function or procedure '" + funcName + "'"); } } return(symbolTable.functionTable[funcName].methodDefinition.ReturnType); } else if (expr.Term.Name == "memberCall") { return(symbolTable.functionTable[GetIdentifier(expr)].methodDefinition.ReturnType); } else if (expr.Term.Name == "varType") { switch (expr.ChildNodes[0].Token.ValueString) { case "int": return(typeof(int)); case "real": return(typeof(double)); default: throw new Exception("Did not recognize type: " + expr.ChildNodes[0].Token.ValueString); } } else if (expr.Term.Name == "initExpr") { return(TypeOfAny(symbolTable, expr.ChildNodes[0].ChildNodes.ToArray()).MakeArrayType()); } else { throw new System.Exception("don't know how to calculate the type of " + expr.Term.Name); } }
private void GenExpr(ParseTreeNode expr, System.Type expectedType, ILGenerator il, SymbolTable symbolTable) { Type deliveredType; if (expr.Term.Name == "stringLiteral") { deliveredType = typeof(string); il.Emit(OpCodes.Ldstr, expr.Token.ValueString); } else if (expr.Term.Name == "number") { if (expr.Token.Value is int) { deliveredType = typeof(int); il.Emit(OpCodes.Ldc_I4, (int)expr.Token.Value); } else { deliveredType = typeof(double); il.Emit(OpCodes.Ldc_R8, float.Parse(expr.Token.ValueString)); } } else if (expr.Term.Name == "binExpr") { Type innerExpectedType = TypeOfAny(symbolTable, expr.ChildNodes[0], expr.ChildNodes[2]); if (new string[] { "=", ">", "<", ">=", "<=", "!=", "~=", "not=", "and", "or", "xor" }.Contains(expr.ChildNodes[1].Term.Name)) { deliveredType = typeof(bool); } else { deliveredType = innerExpectedType; } GenExpr(expr.ChildNodes[0], innerExpectedType, il, symbolTable); GenExpr(expr.ChildNodes[2], innerExpectedType, il, symbolTable); if (deliveredType == typeof(bool)) { switch (expr.ChildNodes[1].Term.Name) { case "=": il.Emit(OpCodes.Ceq); break; case "<": il.Emit(OpCodes.Clt); break; case ">": il.Emit(OpCodes.Cgt); break; case "<=": il.Emit(OpCodes.Cgt); il.Emit(OpCodes.Not); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.And); break; case ">=": il.Emit(OpCodes.Clt); il.Emit(OpCodes.Not); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.And); break; default: throw new Exception("Unrecognized operator " + expr.ChildNodes[1].Term.Name); } } else if (deliveredType == typeof(string)) { switch (expr.ChildNodes[1].Term.Name) { case "+": il.Emit(OpCodes.Call, typeof(System.String).GetMethod("Concat", new System.Type[] { typeof(string), typeof(string) })); break; default: throw new Exception("Unrecognized operator " + expr.ChildNodes[1].Term.Name); } } else { switch (expr.ChildNodes[1].Term.Name) { case "+": il.Emit(OpCodes.Add); break; case "*": il.Emit(OpCodes.Mul); break; case "-": il.Emit(OpCodes.Sub); break; case "/": il.Emit(OpCodes.Div); break; case "div": il.Emit(OpCodes.Div); expectedType = typeof(int); break; case "mod": il.Emit(OpCodes.Rem); break; default: throw new Exception("Unrecognized operator " + expr.ChildNodes[1].Term.Name); } } } else if (expr.Term.Name == "identifier") { string ident = expr.Token.ValueString; symbolTable.PushVar(ident, il); deliveredType = TypeOfExpr(expr, symbolTable); if (deliveredType == typeof(float)) { throw new NotImplementedException(); } } else if (expr.Term.Name == "functionCall" | expr.Term.Name == "memberCall") { deliveredType = TypeOfExpr(expr, symbolTable); if (deliveredType == typeof(float)) { throw new NotImplementedException(); } string funcName = GetIdentifier(expr); if (!symbolTable.functionTable.ContainsKey(funcName)) { if (symbolTable.HasVar(funcName) && symbolTable.TypeOfVar(funcName).IsArray) { //this is an array, return the appropriate value symbolTable.PushVar(funcName, il); if (expr.ChildNodes[1].ChildNodes.Count > 1) { throw new NotImplementedException("Multi-Dimensional arrays are not yet supported"); } this.GenExpr(expr.ChildNodes[1].ChildNodes[0], typeof(int), il, symbolTable); il.Emit(OpCodes.Stelem, symbolTable.TypeOfVar(funcName).GetElementType()); } else { throw new System.Exception("undeclared function or procedure '" + funcName + "'"); } } else { var parameters = symbolTable.functionTable[funcName].arguments; int currentArgument = 0; foreach (var arg in GetArgs(expr))//expr.ChildNodes[1].ChildNodes) { this.GenExpr(arg, parameters[currentArgument].argType, il, symbolTable); currentArgument++; } il.Emit(OpCodes.Call, symbolTable.functionTable[funcName].methodDefinition); } } else if (expr.Term.Name == "initExpr") { deliveredType = TypeOfAny(symbolTable, expr.ChildNodes[0].ChildNodes.ToArray()); int arraySize = expr.ChildNodes[0].ChildNodes.Count; //LocalBuilder paramValues = il.DeclareLocal(deliveredType.MakeArrayType()); //paramValues.SetLocalSymInfo("parameters"); il.Emit(OpCodes.Ldc_I4_S, arraySize); il.Emit(OpCodes.Newarr, deliveredType); //il.Emit(OpCodes.Stloc, paramValues); for (int i = 0; i < expr.ChildNodes[0].ChildNodes.Count; i++) { il.Emit(OpCodes.Dup); il.Emit(OpCodes.Ldc_I4, i); GenExpr(expr.ChildNodes[0].ChildNodes[i], deliveredType, il, symbolTable); il.Emit(OpCodes.Stelem, deliveredType); } deliveredType = deliveredType.MakeArrayType(); } else if (expr.Term.Name == "skip") { deliveredType = typeof(string); il.Emit(OpCodes.Ldstr, Environment.NewLine); } else { throw new System.Exception("don't know how to generate " + expr.Term.Name); } if (deliveredType != expectedType) { if (deliveredType == typeof(int) && expectedType == typeof(string)) { il.Emit(OpCodes.Box, typeof(int)); il.Emit(OpCodes.Callvirt, typeof(object).GetMethod("ToString")); } else if (deliveredType == typeof(double) && expectedType == typeof(string)) { il.Emit(OpCodes.Box, typeof(double)); il.Emit(OpCodes.Callvirt, typeof(object).GetMethod("ToString")); } else if (expectedType == null)//if the expected type is null then it doesn't matter what you give it { } else { throw new System.Exception("can't coerce a " + deliveredType.Name + " to a " + expectedType.Name); } } }