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
        }
예제 #2
0
        //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;
        }