public override void CheckSemantic(Scope scope, List<Error> errors) { #region declaracion de variables utilizadas HashSet<string> typesNames = new HashSet<string>(); var graphNodes = new Dictionary<string, TypeDecNode>(); List<RecordDecNode> firstsRecordDecs = new List<RecordDecNode>(); List<TypeDecNode> redefinedDecs = new List<TypeDecNode>(); Dictionary<string, List<string>> reverseGraph; Dictionary<string, List<string>> graph; #endregion #region detectar redefiniciones y almacenar para procesarlas, añadir records no repetidos al scope, detectar nodos del grafo foreach (TypeDecNode typeDec in Declarations) if (scope.GetType(typeDec.TypeName,false) != null || !typesNames.Add(typeDec.TypeName))//detectar redefiniciones y almacenar para procesarlos al final { errors.Add(new Error(typeDec.GetChild(0),"No es posible definir un tipo con el nombre '{0}' debido a que existe otro tipo con igual nombre dentro de un mismo 'let'", typeDec.TypeName)); HasError = true; if (typeDec is RecordDecNode) typeDec.RelatedType = new RecordType(typeDec.TypeName); redefinedDecs.Add(typeDec); } else if (typeDec is RecordDecNode)//poner el tipo y añadir al scope { firstsRecordDecs.Add((RecordDecNode)typeDec); typeDec.RelatedType = new RecordType(typeDec.TypeName); scope.AddType(typeDec.TypeName, typeDec.RelatedType); } else //es alias o array graphNodes.Add(typeDec.TypeName, typeDec); //añadir el nodo al grafo #endregion #region añadir las aristas al grafo y al reverso del grafo a partir de los nodos del grafo CreateGraph(graphNodes, out graph, out reverseGraph); #endregion #region detectar nodos que pertenecen a ciclos usando SCC y procesarlos List<List<string>> scc = SCC(graph, reverseGraph); foreach (var component in scc) //si la componente tiene mas de un nodo || tiene un nodo con una referencia a si mismo (los nodos tienen siempre 0 o 1 referenecia) if (component.Count > 1 || (graph[component[0]].Count == 1 && graph[component[0]][0].CompareTo(component[0]) == 0)) //todos los nodos de la componente son invalidos foreach (string s in component) { TypeDecNode node = graphNodes[s]; graphNodes.Remove(s); //eliminar s del grafo para convertirlo en un DAG //reportar error errors.Add(new Error(node.GetChild(0),"El tipo '{0}' está definido en función de si mismo",s)); //procesar los nodos invalidos if (node is AliasDecNode)//alias -> RelatedType = Undef node.RelatedType = UndefinedType.UndefinedInstance; if (node is ArrayDecNode)//array -> RelatedType = new Array(Undef) node.RelatedType = new ArrayType(UndefinedType.UndefinedInstance, node.TypeName); scope.AddType(s,node.RelatedType); } #endregion #region hallar el subgrafo que es un DAG y hacer order topologico invertido CreateGraph(graphNodes, out graph, out reverseGraph, false); //el reverso no es necesario en este caso List<string> order = ReversedTopologicalSort(graph); #endregion #region chequear semantica de los nodos en el orden topologico invertido y añadirlos al scope foreach (string s in order) { var node = graphNodes[s]; node.CheckSemantic(scope, errors); scope.AddType(s,node.RelatedType); } #endregion #region chequear semantica de los records foreach (var recordDec in firstsRecordDecs) recordDec.CheckSemantic(scope, errors); //ya se añadieron al scope #endregion #region chequear semantica de los repetidos foreach (var redefinedDec in redefinedDecs) redefinedDec.CheckSemantic(scope, errors); //no se añaden al scope pq estan repetidos #endregion }
//filePathInput indica si input es el codigo fuente o la direccion del archivo donde este se encuentre public bool Compile(string input, string outputfileName, bool filePathInput = true) { Errors = Errors ?? new List<Error>(); Errors.Clear(); ICharStream source; try { source = filePathInput ? new ANTLRFileStream(input) : new ANTLRStringStream(input); //escoger la entrada } catch (Exception) { Errors.Add(new Error(new CommonTree {Line = 0, CharPositionInLine = 0}, "File '{0}' cannot be found",input)); return false; } TigerParser parser = new TigerParser(new CommonTokenStream(new TigerLexer(source, Errors)), Errors); //crear el parser a partir del lexer a partir del source parser.TreeAdaptor = new TigerTreeAdaptor();//setear el tree adaptor del parser para transformar los nodos del AST a nodos de la jerarquia //chequeo sintactico ASTNode ast = parser.program().Tree as ASTNode; if (Errors.Count > 0) { Errors.Sort(); return false; } //chequeo semantico Scope scope = new Scope(); Environment.ResetName(); scope.AddType("int", IntType.IntInstance); scope.AddType("string", StringType.StringInstance); FunctionDecNode printFunct, printiFunct, printlnFunct, getCharFunct, getlnFunct, chrFunct, sizeFunct, substringFunct, concatFunct, notFunct, exitFunct, flushFunct, ordFunct; BuiltInFunctions.DefineBuiltinFunctions(scope, out printFunct, out printiFunct, out printlnFunct, out getCharFunct, out getlnFunct, out chrFunct, out sizeFunct, out substringFunct, out concatFunct, out notFunct, out exitFunct, out flushFunct, out ordFunct); ast.CheckSemantic(scope, Errors); if (Errors.Count > 0) { Errors.Sort(); return false; } //generacion de codigo AssemblyName name = new AssemblyName("TigerProgram"); AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave, Path.GetDirectoryName(outputfileName)); ModuleBuilder moduleBuilder = asmBuilder.DefineDynamicModule("TigerProgram", Path.GetFileName(outputfileName)); TypeBuilder typeBuilder = moduleBuilder.DefineType("Program"); MethodBuilder methodBuilder = typeBuilder.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[] { }); ILGenerator ilGenerator = methodBuilder.GetILGenerator(); LocalBuilder returnValue = ilGenerator.DeclareLocal(typeof(int)); ilGenerator.Emit(OpCodes.Ldc_I4_0); ilGenerator.Emit(OpCodes.Stloc, returnValue); BuiltInFunctions.GenerateBuiltinCode(printFunct, printiFunct, printlnFunct, getCharFunct, getlnFunct, chrFunct, sizeFunct, substringFunct, concatFunct, notFunct, exitFunct, flushFunct, ordFunct, typeBuilder); LocalBuilder varException = ilGenerator.DeclareLocal(typeof(Exception)); ilGenerator.BeginExceptionBlock(); ast.GenerateCode(ilGenerator, typeBuilder, moduleBuilder); if (ast is ExpressionNode && ((ExpressionNode)ast).ReturnType != VoidType.VoidInstance) ilGenerator.Emit(OpCodes.Pop); ilGenerator.BeginCatchBlock(typeof(Exception)); ilGenerator.Emit(OpCodes.Stloc, varException); ilGenerator.Emit(OpCodes.Ldstr, "Exception of type ‘{0}’ was thrown."); ilGenerator.Emit(OpCodes.Ldloc, varException); ilGenerator.EmitCall(OpCodes.Callvirt, typeof(Exception).GetMethod("GetType"), null); ilGenerator.EmitCall(OpCodes.Callvirt, varException.GetType().GetMethod("ToString"), null); ilGenerator.EmitCall(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string), typeof(object) }), null); ilGenerator.Emit(OpCodes.Ldc_I4_1); ilGenerator.Emit(OpCodes.Stloc, returnValue); ilGenerator.EndExceptionBlock(); ilGenerator.Emit(OpCodes.Ldloc, returnValue); ilGenerator.Emit(OpCodes.Ret); typeBuilder.CreateType(); asmBuilder.SetEntryPoint(methodBuilder); asmBuilder.Save(Path.GetFileName(outputfileName)); return true; }