public static void DefineBuiltinFunctions(Scope scope, out FunctionDecNode printFunct, out FunctionDecNode printiFunct, out FunctionDecNode printlineFunct, out FunctionDecNode getCharFunct, out FunctionDecNode getlineFunct, out FunctionDecNode chrFunct, out FunctionDecNode sizeFunct, out FunctionDecNode substringFunct, out FunctionDecNode concatFunct, out FunctionDecNode notFunct, out FunctionDecNode exitFunct, out FunctionDecNode flushFunct, out FunctionDecNode ordFunct)
        {
            // print() Function
            printFunct = new FunctionDecNode();
            printFunct.Name = "print";
            printFunct.Arguments = new List<FunctionVariableDecNode>() { new FunctionVariableDecNode() { RelatedType = StringType.StringInstance, VariableName = "text" } };
            printFunct.RelatedType = VoidType.VoidInstance;
            scope.AddFunVar("print", printFunct);

            // printline() Function
            printlineFunct = new FunctionDecNode();
            printlineFunct.Name = "printline";
            printlineFunct.Arguments = new List<FunctionVariableDecNode>() { new FunctionVariableDecNode() { RelatedType = StringType.StringInstance, VariableName = "text" } };
            printlineFunct.RelatedType = VoidType.VoidInstance;
            scope.AddFunVar("printline", printlineFunct);

            // printi() Function
            printiFunct = new FunctionDecNode();
            printiFunct.Name = "printi";
            printiFunct.Arguments = new List<FunctionVariableDecNode>() { new FunctionVariableDecNode() { RelatedType = IntType.IntInstance, VariableName = "number" } };
            printiFunct.RelatedType = VoidType.VoidInstance;
            scope.AddFunVar("printi", printiFunct);

            //getchar():string  Function
            getCharFunct = new FunctionDecNode();
            getCharFunct.Name = "getchar";
            getCharFunct.Arguments = new List<FunctionVariableDecNode>();
            getCharFunct.RelatedType = StringType.StringInstance;
            scope.AddFunVar("getchar", getCharFunct);

            //getcharln():string  Function
            getlineFunct = new FunctionDecNode();
            getlineFunct.Name = "getline";
            getlineFunct.Arguments = new List<FunctionVariableDecNode>();
            getlineFunct.RelatedType = StringType.StringInstance;
            scope.AddFunVar("getline", getlineFunct);

            //chr(i:int):string  Function
            chrFunct = new FunctionDecNode();
            chrFunct.Name = "chr";
            chrFunct.Arguments = new List<FunctionVariableDecNode>() { new FunctionVariableDecNode() { RelatedType = IntType.IntInstance, VariableName = "number" } };
            chrFunct.RelatedType = StringType.StringInstance;
            scope.AddFunVar("chr", chrFunct);

            //size(s:string): int  Function
            sizeFunct = new FunctionDecNode();
            sizeFunct.Name = "size";
            sizeFunct.Arguments = new List<FunctionVariableDecNode>() { new FunctionVariableDecNode() { RelatedType = StringType.StringInstance, VariableName = "strg" } };
            sizeFunct.RelatedType = IntType.IntInstance;
            scope.AddFunVar("size", sizeFunct);

            //substring(s:string , first:int, n:int): int  Function
            substringFunct = new FunctionDecNode();
            substringFunct.Name = "substring";
            substringFunct.Arguments = new List<FunctionVariableDecNode>() { new FunctionVariableDecNode() { RelatedType = StringType.StringInstance, VariableName = "s" }, new FunctionVariableDecNode() { RelatedType = IntType.IntInstance, VariableName = "first" }, new FunctionVariableDecNode() { RelatedType = IntType.IntInstance, VariableName = "n" } };
            substringFunct.RelatedType = StringType.StringInstance;
            scope.AddFunVar("substring", substringFunct);

            //concat(s1:string ,s1:string ):string  Function
            concatFunct = new FunctionDecNode();
            concatFunct.Name = "concat";
            concatFunct.Arguments = new List<FunctionVariableDecNode>() { new FunctionVariableDecNode() { RelatedType = StringType.StringInstance, VariableName = "s1" }, new FunctionVariableDecNode() { RelatedType = StringType.StringInstance, VariableName = "s2" } };
            concatFunct.RelatedType = StringType.StringInstance;
            scope.AddFunVar("concat", concatFunct);

            //not(i:int ):int  Function
            notFunct = new FunctionDecNode();
            notFunct.Name = "not";
            notFunct.Arguments = new List<FunctionVariableDecNode>() { new FunctionVariableDecNode() { RelatedType = IntType.IntInstance, VariableName = "i" } };
            notFunct.RelatedType = IntType.IntInstance;
            scope.AddFunVar("not", notFunct);

            //exit(i:int ):int  Function
            exitFunct = new FunctionDecNode();
            exitFunct.Name = "exit";
            exitFunct.Arguments = new List<FunctionVariableDecNode>() { new FunctionVariableDecNode() { RelatedType = IntType.IntInstance, VariableName = "exitcode" } };
            exitFunct.RelatedType = VoidType.VoidInstance;
            scope.AddFunVar("exit", exitFunct);

            //flush ()  Function
            flushFunct = new FunctionDecNode();
            flushFunct.Name = "flush";
            flushFunct.Arguments = new List<FunctionVariableDecNode>();
            flushFunct.RelatedType = VoidType.VoidInstance;
            scope.AddFunVar("flush", flushFunct);

            //ord(s:string): int  Function
            ordFunct = new FunctionDecNode();
            ordFunct.Name = "ord";
            ordFunct.Arguments = new List<FunctionVariableDecNode>() { new FunctionVariableDecNode() { RelatedType = StringType.StringInstance, VariableName = "str" } };
            ordFunct.RelatedType = IntType.IntInstance;
            scope.AddFunVar("ord", ordFunct);
        }
        public static void GenerateBuiltinCode(FunctionDecNode printFunct, FunctionDecNode printiFunct, FunctionDecNode printlineFunct, FunctionDecNode getCharFunct, FunctionDecNode getlineFunct, FunctionDecNode chrFunct, FunctionDecNode sizeFunct, FunctionDecNode substringFunct, FunctionDecNode concatFunct, FunctionDecNode notFunct, FunctionDecNode exitFunct, FunctionDecNode flushFunct, FunctionDecNode ordFunct, TypeBuilder typeBuilder)
        {
            MethodBuilder methodBuilder;
            ILGenerator ilGen;

            // print(s:string) ----------------------------------------------------------
            if (UsedFunctions.Contains("print"))
            {
                methodBuilder = typeBuilder.DefineMethod("print", MethodAttributes.Public | MethodAttributes.Static,
                                                         typeof (void), new Type[] {typeof (string)});
                ilGen = methodBuilder.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Call, typeof (Console).GetMethod("Write", new Type[] {typeof (string)}));
                ilGen.Emit(OpCodes.Ret);
                printFunct.MethodBuilder = methodBuilder;
            }

            // printline(s:string) ----------------------------------------------------------
            if (UsedFunctions.Contains("printline"))
            {
                methodBuilder = typeBuilder.DefineMethod("printline", MethodAttributes.Public | MethodAttributes.Static,
                                                         typeof (void), new Type[] {typeof (string)});
                ilGen = methodBuilder.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Call, typeof (Console).GetMethod("WriteLine", new Type[] {typeof (string)}));
                ilGen.Emit(OpCodes.Ret);
                printlineFunct.MethodBuilder = methodBuilder;
            }

            // printi(i:int) ------------------------------------------------------------
            if (UsedFunctions.Contains("printi"))
            {
                methodBuilder = typeBuilder.DefineMethod("printi", MethodAttributes.Public | MethodAttributes.Static,
                                                         typeof (void), new Type[] {typeof (int)});
                ilGen = methodBuilder.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Call, typeof (Console).GetMethod("Write", new Type[] {typeof (int)}));
                ilGen.Emit(OpCodes.Ret);
                printiFunct.MethodBuilder = methodBuilder;
            }

            // getchar():string ----------------------------------------------------------
            if (UsedFunctions.Contains("getchar"))
            {
                methodBuilder = typeBuilder.DefineMethod("getchar", MethodAttributes.Public | MethodAttributes.Static,
                                                         typeof (string), new Type[] {});
                ilGen = methodBuilder.GetILGenerator();

                Label ok = ilGen.DefineLabel();
                ilGen.Emit(OpCodes.Call, typeof (Console).GetMethod("Read", new Type[] {}));

                ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Ldc_I4, 10);
                ilGen.Emit(OpCodes.Bne_Un, ok);

                ilGen.Emit(OpCodes.Pop); // sacar el 10
                ilGen.Emit(OpCodes.Call, typeof (Console).GetMethod("Read", new Type[] {}));
                ilGen.Emit(OpCodes.Pop); // sacar el 13
                ilGen.Emit(OpCodes.Ldstr, "");
                ilGen.Emit(OpCodes.Ret);

                ilGen.MarkLabel(ok);

                ilGen.Emit(OpCodes.Conv_U2);
                ilGen.Emit(OpCodes.Call, typeof (Char).GetMethod("ToString", new Type[] {typeof (char)}));
                ilGen.Emit(OpCodes.Ret);

                getCharFunct.MethodBuilder = methodBuilder;
            }

            // getline():string ----------------------------------------------------------
            if (UsedFunctions.Contains("getline"))
            {
                methodBuilder = typeBuilder.DefineMethod("getline", MethodAttributes.Public | MethodAttributes.Static, typeof(string), new Type[] { });
                ilGen = methodBuilder.GetILGenerator();

                ilGen.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadLine", new Type[] { }));
                ilGen.Emit(OpCodes.Ret);

                getlineFunct.MethodBuilder = methodBuilder;
            }

            // chr(i:int):string --------------------------------------------------------
            if (UsedFunctions.Contains("chr"))
            {
                methodBuilder = typeBuilder.DefineMethod("chr", MethodAttributes.Public | MethodAttributes.Static,
                                                         typeof (string), new Type[] {typeof (int)});
                ilGen = methodBuilder.GetILGenerator();
                Label error = ilGen.DefineLabel();

                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Ldc_I4_0);
                ilGen.Emit(OpCodes.Blt, error);

                ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Ldc_I4, 256);
                ilGen.Emit(OpCodes.Bge, error);

                ilGen.Emit(OpCodes.Conv_U2);
                ilGen.Emit(OpCodes.Call, typeof (Char).GetMethod("ToString", new Type[] {typeof (char)}));
                ilGen.Emit(OpCodes.Ret);

                ilGen.MarkLabel(error);
                ilGen.ThrowException(typeof (ArgumentException));
                chrFunct.MethodBuilder = methodBuilder;
            }

            // size(s:string):int ------------------------------------------------------
            if (UsedFunctions.Contains("size"))
            {
                methodBuilder = typeBuilder.DefineMethod("size", MethodAttributes.Public | MethodAttributes.Static,
                                                         typeof (int), new Type[] {typeof (string)});
                ilGen = methodBuilder.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Call, typeof (String).GetMethod("get_Length", Type.EmptyTypes));
                ilGen.Emit(OpCodes.Ret);
                sizeFunct.MethodBuilder = methodBuilder;
            }

            // substring(s:string , first:int, n:int): int ------------------------------
            if (UsedFunctions.Contains("substring"))
            {
                methodBuilder = typeBuilder.DefineMethod("substring", MethodAttributes.Public | MethodAttributes.Static,
                                                         typeof (string),
                                                         new Type[] {typeof (string), typeof (int), typeof (int)});
                ilGen = methodBuilder.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldarg_1);
                ilGen.Emit(OpCodes.Ldarg_2);
                ilGen.Emit(OpCodes.Call, typeof (String).GetMethod("Substring", new Type[] {typeof (int), typeof (int)}));
                ilGen.Emit(OpCodes.Ret);
                substringFunct.MethodBuilder = methodBuilder;
            }

            // concat(s1 : string ,s2 : string) : string --------------------------------
            if (UsedFunctions.Contains("concat"))
            {
                methodBuilder = typeBuilder.DefineMethod("concat", MethodAttributes.Public | MethodAttributes.Static,
                                                         typeof (string), new Type[] {typeof (string), typeof (string)});
                ilGen = methodBuilder.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldarg_1);
                ilGen.Emit(OpCodes.Call,
                           typeof (String).GetMethod("Concat", new Type[] {typeof (string), typeof (string)}));
                ilGen.Emit(OpCodes.Ret);
                concatFunct.MethodBuilder = methodBuilder;
            }

            // not(i:int):int -----------------------------------------------------------
            if (UsedFunctions.Contains("not"))
            {
                methodBuilder = typeBuilder.DefineMethod("not", MethodAttributes.Public | MethodAttributes.Static,
                                                         typeof (int), new Type[] {typeof (int)});
                ilGen = methodBuilder.GetILGenerator();
                ilGen.Emit(OpCodes.Ldc_I4_0);
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ceq);
                ilGen.Emit(OpCodes.Ret);
                notFunct.MethodBuilder = methodBuilder;
            }

            // exit(i:int):int ----------------------------------------------------------
            if (UsedFunctions.Contains("exit"))
            {
                methodBuilder = typeBuilder.DefineMethod("exit", MethodAttributes.Public | MethodAttributes.Static,
                                                         typeof (void), new Type[] {typeof (int)});
                ilGen = methodBuilder.GetILGenerator();
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Call, typeof (System.Environment).GetMethod("Exit", new Type[] {typeof (int)}));
                ilGen.Emit(OpCodes.Ret);
                exitFunct.MethodBuilder = methodBuilder;
            }

            // flush() ------------------------------------------------------------------
            if (UsedFunctions.Contains("flush"))
            {
                methodBuilder = typeBuilder.DefineMethod("flush", MethodAttributes.Public | MethodAttributes.Static,
                                                         typeof (void), Type.EmptyTypes);
                ilGen = methodBuilder.GetILGenerator();
                ilGen.Emit(OpCodes.Call, typeof (Console).GetMethod("get_Out", Type.EmptyTypes));
                ilGen.Emit(OpCodes.Call, typeof (TextWriter).GetMethod("Flush", Type.EmptyTypes));
                ilGen.Emit(OpCodes.Ret);
                flushFunct.MethodBuilder = methodBuilder;
            }

            // ord(string):int ----------------------------------------------------------
            if (UsedFunctions.Contains("ord"))
            {
                methodBuilder = typeBuilder.DefineMethod("ord", MethodAttributes.Public | MethodAttributes.Static,
                                                         typeof (int), new Type[] {typeof (string)});
                ilGen = methodBuilder.GetILGenerator();
                Label emptyStr = ilGen.DefineLabel();

                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Call, typeof (String).GetMethod("get_Length", Type.EmptyTypes));
                ilGen.Emit(OpCodes.Brfalse, emptyStr);

                ilGen.Emit(OpCodes.Ldc_I4_0);
                ilGen.Emit(OpCodes.Call, typeof (String).GetMethod("get_Chars", new Type[] {typeof (int)}));
                ilGen.Emit(OpCodes.Ret);

                ilGen.MarkLabel(emptyStr);

                ilGen.Emit(OpCodes.Pop);
                ilGen.Emit(OpCodes.Ldc_I4, -1);
                ilGen.Emit(OpCodes.Ret);
                ordFunct.MethodBuilder = methodBuilder;
            }
        }