예제 #1
0
 public List<Errors.CompilerWarning> Optimize(program_node p)
 {
     try
     {
         foreach (common_namespace_node cnn in p.common_namespaces)
         {
             VisitCommonNamespaceHeader(cnn);
         }
         foreach (common_namespace_node cnn in p.common_namespaces)
         {
             VisitCommonNamespaceNode(cnn);
         }
         if (p.main_function != null)
             VisitStatement(p.main_function.function_code);
         foreach (common_namespace_node cnn in p.common_namespaces)
         {
             CollectInfoNamespaces(cnn);
         }
         return warns;
     }
     catch (Exception e)
     {
         return warns;
     }
 }
 public void ClearAll()
 {
     _semantic_tree = null;
     PCUReader.CloseUnits(); 
     PCUWriter.Clear();
     RecompileList.Clear();
     CycleUnits.Clear();
     UnitTable.Clear();
     UnitsSortedList.Clear();
     //TreeRealization.PCUReturner.Clear();
     BadNodesInSyntaxTree.Clear();
     PCUReader.AllReaders.Clear();
     project = null;
     StandarModules.Clear();
     //SystemLibrary.SystemLibrary.RestoreStandartNames();
 }
		public string Compile()
        {
			
			try
            {
                //var timer = System.Diagnostics.Stopwatch.StartNew(); //////

                if (Path.GetExtension(CompilerOptions.SourceFileName) == ".vb")
                {
                    return CompileVB();
                }

                if (Path.GetExtension(CompilerOptions.SourceFileName) == ".cs")
                {
                    return CompileCS();
                }
                
				OnChangeCompilerState(this, CompilerState.CompilationStarting, CompilerOptions.SourceFileName);

                Reset();
                //Console.WriteLine(timer.ElapsedMilliseconds / 1000.0);  //////
                if (CompilerOptions.ProjectCompiled)
                {
                	PrepareCompileOptionsForProject();
                }
                Environment.CurrentDirectory = CompilerOptions.SourceFileDirectory; // нужно для подключения *.inc и *.resources
                Units = new PascalABCCompiler.TreeRealization.unit_node_list();
                CurrentSyntaxUnit = new SyntaxTree.uses_unit_in(new SyntaxTree.string_const(CompilerOptions.SourceFileName));
                CompileUnit(Units, CurrentSyntaxUnit);
                //Console.WriteLine(timer.ElapsedMilliseconds / 1000.0);  //////
                foreach (CompilationUnit CurrentUnit in UnitsToCompile)
                    if (CurrentUnit.State != UnitState.Compiled)
                    {
                        CurrentCompilationUnit = CurrentUnit;
                        string UnitName = GetUnitFileName(CurrentUnit.SyntaxUnitName);
                        //if(CurrentUnit.State!=UnitState.InterfaceCompiled)													//DEBUG
                        //Console.WriteLine("ERROR! interface not compiled "+GetUnitFileName(CurrentUnit.SyntaxUnitName));//DEBUG
                        System.Collections.Generic.List<SyntaxTree.unit_or_namespace> SyntaxUsesList = GetSyntaxImplementationUsesList(CurrentUnit.SyntaxTree);
                        CurrentUnit.PossibleNamespaces.Clear();
                        if (SyntaxUsesList != null)
                        {
                            for (int i = SyntaxUsesList.Count - 1; i >= 0; i--)
                                if (!IsPossibleNamespace(SyntaxUsesList[i], false))
                                {
                                    compilerOptions.UseDllForSystemUnits = false;
                                    break;
                                }
                            for (int i = SyntaxUsesList.Count - 1; i >= 0; i--)
                                if (!IsPossibleNamespace(SyntaxUsesList[i], true))
                                    CompileUnit(CurrentUnit.ImplementationUsedUnits, SyntaxUsesList[i]);
                                else
                                {
                                    CurrentUnit.ImplementationUsedUnits.AddElement(new TreeRealization.namespace_unit_node(GetNamespace(SyntaxUsesList[i])));
                                    CurrentUnit.PossibleNamespaces.Add(SyntaxUsesList[i]);
                                }
                        }
                        //Console.WriteLine("Compile Implementation "+UnitName);//DEBUG
                        //TODO: Избавиться от преобразования типа.

                        AddNamespaces(CurrentUnit.ImplementationUsingNamespaceList, CurrentUnit.PossibleNamespaces, true);

#if DEBUG
                        if (InternalDebug.SemanticAnalysis)
#endif
                        {
                            OnChangeCompilerState(this, CompilerState.CompileImplementation, UnitName);
                            PascalABCCompiler.TreeConverter.SemanticRules.SymbolTableCaseSensitive = CurrentUnit.CaseSensitive;
                            SyntaxTreeToSemanticTreeConverter.CompileImplementation(
                                (PascalABCCompiler.TreeRealization.common_unit_node)CurrentUnit.SemanticTree,
                                CurrentUnit.SyntaxTree,
                                buildImplementationUsesList(CurrentUnit),
                                ErrorsList,Warnings,
                                CurrentUnit.syntax_error, BadNodesInSyntaxTree,
                                CurrentUnit.InterfaceUsingNamespaceList,
                                CurrentUnit.ImplementationUsingNamespaceList,
                                null,
                                CompilerOptions.Debug,
                                CompilerOptions.ForDebugging
                                );
                            CheckErrors();
                        }
                        CurrentUnit.State = UnitState.Compiled;
                        OnChangeCompilerState(this, CompilerState.EndCompileFile, UnitName);
                        //SavePCU(CurrentUnit, UnitName);
                        CurrentUnit.UnitName = UnitName;
                    }

                ClosePCUReadersAndWriters();
                if (CompilerOptions.SaveDocumentation)
                SaveDocumentations();
                
                compilerDirectives = GetCompilerDirectives(UnitsSortedList);


                TreeRealization.compiler_directive compilerDirective;
                //TODO сделать это понормальному!!!!!
                if (compilerDirectives.ContainsKey(TreeConverter.compiler_string_consts.compiler_directive_apptype))
                {
                    string directive = compilerDirectives[TreeConverter.compiler_string_consts.compiler_directive_apptype][0].directive;
                    if (string.Compare(directive,"console",true)==0)
                        CompilerOptions.OutputFileType = CompilerOptions.OutputType.ConsoleApplicaton;
                    else
                        if (string.Compare(directive,"windows",true)==0)
                            CompilerOptions.OutputFileType = CompilerOptions.OutputType.WindowsApplication;
                        else
                            if (string.Compare(directive,"dll",true)==0)
                                CompilerOptions.OutputFileType = CompilerOptions.OutputType.ClassLibrary;
                            else
                                if (string.Compare(directive,"pcu",true)==0)
                                    CompilerOptions.OutputFileType = CompilerOptions.OutputType.PascalCompiledUnit;
                }

                moveSystemUnitToForwardUnitSortedList();
                PascalABCCompiler.TreeRealization.common_unit_node system_unit = null;
                if (UnitsSortedList.Count>0) 
                    system_unit = UnitsSortedList[0].SemanticTree as PascalABCCompiler.TreeRealization.common_unit_node;
                if (system_unit != null)
                    system_unit.IsConsoleApplicationVariable = CompilerOptions.OutputFileType == CompilerOptions.OutputType.ConsoleApplicaton;

                TreeRealization.program_node pn = null;
                NETGenerator.CompilerOptions cdo = new NETGenerator.CompilerOptions();
                List<TreeRealization.compiler_directive> cds;
                if (compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.compiler_directive_platformtarget, out cds))
                {
                    string plt = cds[0].directive.ToLower();
                    if (plt.Equals("x86"))
                        cdo.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.x86;
                    else if (plt.Equals("x64"))
                        cdo.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.x64;
                    else if (plt.Equals("anycpu"))
                        cdo.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.AnyCPU;
                }
                if (this.compilerOptions.Only32Bit)
                    cdo.platformtarget = NETGenerator.CompilerOptions.PlatformTarget.x86;
                if (compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.product_string, out cds))
                {
                    cdo.Product = cds[0].directive;
                }
                if (compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.version_string, out cds))
                {
                    cdo.ProductVersion = cds[0].directive;
                }
                if (compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.company_string, out cds))
                {
                    cdo.Company = cds[0].directive;
                }
                if (compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.trademark_string, out cds))
                {
                    cdo.TradeMark = cds[0].directive;
                }
                if (compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.copyright_string, out cds))
                {
                    cdo.Copyright = cds[0].directive;
                }
                if (compilerDirectives.TryGetValue(TreeConverter.compiler_string_consts.main_resource_string, out cds))
                {
                    cdo.MainResourceFileName = cds[0].directive;
                    if (!File.Exists(cdo.MainResourceFileName))
                    {
                        ErrorsList.Add(new ResourceFileNotFound(cds[0].directive, cds[0].location));
                    }
                }

                List<string> ResourceFiles = null;
                if (compilerDirectives.ContainsKey(TreeConverter.compiler_string_consts.compiler_directive_resource))
                {
                    ResourceFiles = new List<string>();
                    List<TreeRealization.compiler_directive> ResourceDirectives = compilerDirectives[TreeConverter.compiler_string_consts.compiler_directive_resource];
                    foreach (TreeRealization.compiler_directive cd in ResourceDirectives)
                        if (!File.Exists(cd.directive))
                        {
                            string fileName = Path.Combine(cd.location.doc.file_name, cd.directive);
                            if (File.Exists(fileName))
                                ResourceFiles.Add(fileName);
                            else
                                ErrorsList.Add(new ResourceFileNotFound(cd.directive, cd.location));
                        }
                        else
                            ResourceFiles.Add(cd.directive);
                }
                string res_file = null;
                if (project != null)
                {
                    if (!(project.major_version == 0 && project.minor_version == 0 && project.build_version == 0 && project.revision_version == 0))
                        cdo.ProductVersion = project.major_version + "." + project.minor_version + "." + project.build_version + "." + project.revision_version;
                    if (!string.IsNullOrEmpty(project.product))
                        cdo.Product = project.product;
                    if (!string.IsNullOrEmpty(project.company))
                        cdo.Company = project.company;
                    if (!string.IsNullOrEmpty(project.trademark))
                        cdo.TradeMark = project.trademark;
                    if (!string.IsNullOrEmpty(project.copyright))
                        cdo.Copyright = project.copyright;
                    if (!string.IsNullOrEmpty(project.app_icon) && false)
                    {
                        //cdo.MainResourceFileName = project.app_icon;
                        string rc_file = Path.GetFileNameWithoutExtension(project.app_icon) + ".rc";
                        StreamWriter sw = File.CreateText(rc_file);
                        sw.WriteLine("1 ICON \"" + project.app_icon.Replace("\\", "\\\\") + "\"");
                        if (cdo.NeedDefineVersionInfo)
                        {
                            cdo.NeedDefineVersionInfo = false;
                            sw.WriteLine("1 VERSIONINFO");
                            string ver = project.major_version + "," + project.minor_version + "," + project.build_version + "," + project.revision_version;
                            sw.WriteLine("FILEVERSION " + ver);
                            /*sw.WriteLine("FILEFLAGSMASK VS_FFI_FILEFLAGSMASK");
                            sw.WriteLine("FILEFLAGS VER_DEBUG");
                            sw.WriteLine("FILEOS VOS__WINDOWS32");
                            if (project.project_type != ProjectType.Library)
                                sw.WriteLine("FILETYPE VFT_APP");
                            else
                                sw.WriteLine("FILETYPE VFT_DLL");
                            sw.WriteLine("FILESUBTYPE VFT2_UNKNOWN");*/
                            sw.WriteLine("BEGIN \r\n BLOCK \"StringFileInfo\"\r\n BEGIN \r\n BLOCK \"041904E3\"\r\nBEGIN");
                            sw.WriteLine("VALUE \"ProductName\"," + "\"" + cdo.Product + "\"");
                            sw.WriteLine("VALUE \"FileVersion\"," + "\"" + ver + "\"");
                            sw.WriteLine("VALUE \"ProductVersion\"," + "\"" + ver + "\"");
                            sw.WriteLine("VALUE \"FileDescription\"," + "\"" + "" + "\"");
                            sw.WriteLine("VALUE \"OriginalFileName\"," + "\"" + Path.GetFileName(CompilerOptions.OutputFileName) + "\"");
                            sw.WriteLine("VALUE \"InternalName\"," + "\"" + Path.GetFileNameWithoutExtension(CompilerOptions.OutputFileName) + "\"");
                            sw.WriteLine("VALUE \"CompanyName\"," + "\"" + cdo.Company + "\"");
                            sw.WriteLine("VALUE \"LegalTrademarks1\"," + "\"" + cdo.TradeMark + "\"");
                            sw.WriteLine("VALUE \"LegalCopyright\"," + "\"" + cdo.Copyright + "\"");
                            sw.WriteLine("END");
                            sw.WriteLine("END");

                            sw.WriteLine("BLOCK \"VarFileInfo\"\r\nBEGIN");
                            sw.WriteLine("VALUE \"Translation\", 0x0419, 1251");
                            sw.WriteLine("END");
                            sw.WriteLine("END");
                        }
                        sw.Close();
                        System.Diagnostics.Process prc = new System.Diagnostics.Process();
                        prc.StartInfo.FileName = Path.Combine(this.CompilerOptions.SystemDirectory, "rc.exe");
                        prc.StartInfo.Arguments = Path.Combine(Path.GetDirectoryName(project.app_icon), Path.GetFileNameWithoutExtension(project.app_icon) + ".rc");
                        prc.StartInfo.CreateNoWindow = true;
                        prc.StartInfo.UseShellExecute = false;
                        prc.StartInfo.RedirectStandardOutput = true;
                        prc.StartInfo.RedirectStandardError = true;
                        prc.Start();
                        prc.WaitForExit();
                        res_file = Path.Combine(Path.GetDirectoryName(project.app_icon), Path.GetFileNameWithoutExtension(project.app_icon) + ".res");
                        if (File.Exists(res_file))
                        {
                            cdo.MainResourceFileName = res_file;
                        }
                        File.Delete(rc_file);
                    }
                }

                if (ErrorsList.Count == 0 && compilerOptions.GenerateCode)
                {
                    cdo.ForRunningWithEnvironment = CompilerOptions.RunWithEnvironment;
                	switch (CompilerOptions.OutputFileType)
                    {
                        case CompilerOptions.OutputType.ClassLibrary: cdo.target = NETGenerator.TargetType.Dll; break;
                        case CompilerOptions.OutputType.ConsoleApplicaton: cdo.target = NETGenerator.TargetType.Exe; break;
                        case CompilerOptions.OutputType.WindowsApplication: cdo.target = NETGenerator.TargetType.WinExe; break;

                    }
                    if (project != null && project.ProjectType == ProjectType.WindowsApp)
                        cdo.target = PascalABCCompiler.NETGenerator.TargetType.WinExe;
                    switch (CompilerOptions.Debug)
                    {
                        case true: cdo.dbg_attrs = NETGenerator.DebugAttributes.Debug; break;
                        case false: cdo.dbg_attrs = NETGenerator.DebugAttributes.Release; break;
                    }
                    if (CompilerOptions.ForDebugging)
                        cdo.dbg_attrs = NETGenerator.DebugAttributes.ForDebbuging;


                    //TODO: Разобратся c location для program_node и правильно передавать main_function. Добавить генератор main_function в SyntaxTreeToSemanticTreeConverter.
                    pn = new PascalABCCompiler.TreeRealization.program_node(null, null);
                    
                    for (int i = 0; i < UnitsSortedList.Count; i++)
                        pn.units.AddElement(UnitsSortedList[i].SemanticTree as TreeRealization.common_unit_node);

                    //(ssyy) Добавил в условие c_module
                    if (FirstCompilationUnit.SyntaxTree is SyntaxTree.program_module ||
                        FirstCompilationUnit.SyntaxTree is SyntaxTree.c_module)
                    {
                        if ((cdo.target == NETGenerator.TargetType.Exe) || (cdo.target == NETGenerator.TargetType.WinExe))
                        {
                            if (UnitsSortedList.Count > 0)
                            {
                                pn.main_function = ((PascalABCCompiler.TreeRealization.common_unit_node)UnitsSortedList[UnitsSortedList.Count - 1].SemanticTree).main_function;
                                /***************************Ivan added*******************************/
                                if (pn.main_function.function_code.location != null)
                                {
                                    bool flag = false;
                                    PascalABCCompiler.TreeRealization.common_namespace_node main_ns = pn.main_function.namespace_node;
                                    for (int i = 0; i < main_ns.variables.Count; i++)
                                    {
                                        PascalABCCompiler.TreeRealization.namespace_variable nv = main_ns.variables[i];
                                        if (nv.inital_value != null && nv.inital_value.location != null && !(nv.inital_value is PascalABCCompiler.TreeRealization.constant_node)
                                            && !(nv.inital_value is PascalABCCompiler.TreeRealization.record_initializer) && !(nv.inital_value is PascalABCCompiler.TreeRealization.array_initializer))
                                        {
                                            varBeginOffset = main_ns.variables[i].inital_value.location.begin_line_num;
                                            flag = true;
                                            break;
                                        }
                                    }
                                    beginOffset = pn.main_function.function_code.location.begin_line_num;
                                }
                                /*******************************************************************/
                                Dictionary<string, object> config_dic = new Dictionary<string, object>();
                                if (CompilerOptions.Locale != null && PascalABCCompiler.StringResourcesLanguage.GetLCIDByTwoLetterISO(CompilerOptions.Locale) != null)
                                { 
                                    config_dic["locale"] = CompilerOptions.Locale;
                                    config_dic["full_locale"] = PascalABCCompiler.StringResourcesLanguage.GetLCIDByTwoLetterISO(CompilerOptions.Locale);
                                }
                                pn.create_main_function(StandarModules.ToArray(), config_dic);
                                
                            }
                        }
                    }
                    else if (FirstCompilationUnit.SyntaxTree is SyntaxTree.unit_module && cdo.target == NETGenerator.TargetType.Dll)
                    {
                    	pn.create_main_function_as_in_module();
                    }
                    pn = semanticTreeConvertersController.Convert(pn) as TreeRealization.program_node;

                    _semantic_tree = pn;

                    if (FirstCompilationUnit.SyntaxTree is SyntaxTree.unit_module && CompilerOptions.OutputFileType != CompilerOptions.OutputType.ClassLibrary)
                    {
                        //если мы комилируем PCU
                        CompilerOptions.OutputFileType = CompilerOptions.OutputType.PascalCompiledUnit;
                    }
                    else
                    {
                        if( CompilerOptions.OutputFileType!= CompilerOptions.OutputType.SemanticTree)
#if DEBUG
                        if (InternalDebug.CodeGeneration)
#endif
                        {
                            try
                            {
                                File.Create(CompilerOptions.OutputFileName).Close();
                                //File.Delete(CompilerOptions.OutputFileName);
                                string pdb_file_name=Path.ChangeExtension(CompilerOptions.OutputFileName, ".pdb");
                                if (File.Exists(pdb_file_name))
                                    File.Delete(pdb_file_name);
                            }
                            catch (Exception)
                            {
                                throw new UnauthorizedAccessToFile(CompilerOptions.OutputFileName);
                            }
                            OnChangeCompilerState(this, CompilerState.CodeGeneration, CompilerOptions.OutputFileName);
                            string[] ResourceFilesArray = null;
                            if (ResourceFiles != null)
                                ResourceFilesArray = ResourceFiles.ToArray();
                            cds = null;
                            /*if (compilerDirectives.TryGetValue("platform", out cds) && cds[0].directive.ToLower() == "native")
                            {
                                //LLVMCodeGeneratorsController.Compile(pn, CompilerOptions.OutputFileName, CompilerOptions.SourceFileName, ResourceFilesArray);
                                PABCToCppCodeGeneratorsController.Compile(pn, CompilerOptions.OutputFileName, CompilerOptions.SourceFileName, ResourceFilesArray);
                            }
                            else*/
                            CodeGeneratorsController.Compile(pn, CompilerOptions.OutputFileName, CompilerOptions.SourceFileName, cdo, CompilerOptions.StandartDirectories, ResourceFilesArray);
                            if (res_file != null)
                                File.Delete(res_file);
                        }
                    }
                }
            }
            catch (TreeConverter.ParserError err)
            {
                //конвертор уткнулся в ошибку. ничего не делаем
            }
            catch (Errors.CompilerInternalError err)
            {
                if (ErrorsList.Count == 0)
                    ErrorsList.Add(err);
                else
                {
#if DEBUG
                    if (!InternalDebug.SkipInternalErrorsIfSyntaxTreeIsCorrupt)
                        ErrorsList.Add(err);
#endif
                }
            }
            catch (Errors.Error err)
            {
                if (ErrorsList.Count == 0)
                    ErrorsList.Add(err);
                else
                    if (err != ErrorsList[0])
                    {
                        if (err is SemanticError)
                        {
                            int pos = ErrorsList.Count;
                            SourceLocation loc = (err as SemanticError).SourceLocation, loctmp;
                            if (loc != null)
                                for (int i = 0; i < ErrorsList.Count; i++)
                                    if (ErrorsList[i] is LocatedError)
                                        if ((loctmp = (ErrorsList[i] as LocatedError).SourceLocation) != null)
                                            if (loctmp > loc)
                                            {
                                                pos = i;
                                                break;
                                            }

                            ErrorsList.Insert(pos, err);
                        }
                        else
                            ErrorsList.Add(err);
                    }
            }
            catch (Exception err)
            {
            	string fn = "Compiler";
                if (CurrentCompilationUnit != null && this.CurrentCompilationUnit.SyntaxTree != null) fn = Path.GetFileName(this.CurrentCompilationUnit.SyntaxTree.file_name);
                Errors.CompilerInternalError comp_err = new Errors.CompilerInternalError(string.Format("Compiler.Compile[{0}]", fn), err);
                if (ErrorsList.Count == 0)
                    ErrorsList.Add(comp_err);
                else
                {
#if DEBUG
                    if (!InternalDebug.SkipInternalErrorsIfSyntaxTreeIsCorrupt)
                        ErrorsList.Add(comp_err);
#endif
                }
            }
            //удаляем лишние ошибки
            /*foreach(Error er in errorsList)
            {

            }*/

            //на случай если мы вывалились по исключению но у нас есть откомпилированные модули
            try
            {
                ClosePCUReadersAndWriters();
            }
            catch (Exception e)
            {
                ErrorsList.Add(new Errors.CompilerInternalError("Compiler.ClosePCUReadersAndWriters", e));
            }
            bool need_recompiled = false;
            if (ErrorsList.Count > 0)
            {
                if (compilerOptions.UseDllForSystemUnits && !has_only_syntax_errors(ErrorsList) && compilerOptions.IgnoreRtlErrors)
                {
                    compilerOptions.UseDllForSystemUnits = false;
                    ErrorsList.Clear();
                    
                    need_recompiled = true;

                }
            }
            OnChangeCompilerState(this, CompilerState.CompilationFinished, CompilerOptions.SourceFileName);
            if (ClearAfterCompilation)
            ClearAll();
            
            
            OnChangeCompilerState(this, CompilerState.Ready, null);
            if (ErrorsList.Count > 0)
            {
                return null;
            }
            else if (need_recompiled)
            {
                //Compiler c = new Compiler(sourceFilesProvider,OnChangeCompilerState);
                //return c.Compile(this.compilerOptions);
                return Compile();
            }
            else
                return CompilerOptions.OutputFileName;
        }