Beispiel #1
0
        public override void Run()
        {
            IWorkbenchWindow window = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow;

            if (window != null && window.ViewContent is IEditable)
            {
                IParser p = ParserFactory.CreateParser(SupportedLanguage.VBNet, new StringReader(((IEditable)window.ViewContent).Text));
                p.Parse();

                if (p.Errors.Count > 0)
                {
                    MessageService.ShowError("${res:ICSharpCode.SharpDevelop.Commands.Convert.CorrectSourceCodeErrors}\n" + p.Errors.ErrorOutput);
                    return;
                }
                ICSharpCode.NRefactory.PrettyPrinter.CSharpOutputVisitor output = new ICSharpCode.NRefactory.PrettyPrinter.CSharpOutputVisitor();
                List <ISpecial> specials = p.Lexer.SpecialTracker.CurrentSpecials;
                PreprocessingDirective.VBToCSharp(specials);
                new VBNetToCSharpConvertVisitor().VisitCompilationUnit(p.CompilationUnit, null);
                using (SpecialNodesInserter.Install(specials, output)) {
                    output.VisitCompilationUnit(p.CompilationUnit, null);
                }

                FileService.NewFile("Generated.CS", "C#", output.Text);
            }
        }
Beispiel #2
0
        public override void Run()
        {
            IViewContent content = WorkbenchSingleton.Workbench.ActiveViewContent;

            if (content != null && content.PrimaryFileName != null && content is IEditable)
            {
                IParser p = ParserFactory.CreateParser(SupportedLanguage.CSharp, new StringReader(((IEditable)content).Text));
                p.Parse();
                if (p.Errors.Count > 0)
                {
                    MessageService.ShowError("${res:ICSharpCode.SharpDevelop.Commands.Convert.CorrectSourceCodeErrors}\n" + p.Errors.ErrorOutput);
                    return;
                }

                VBNetOutputVisitor vbv = new VBNetOutputVisitor();

                List <ISpecial> specials = p.Lexer.SpecialTracker.CurrentSpecials;
                PreprocessingDirective.CSharpToVB(specials);
                IAstVisitor v = new CSharpToVBNetConvertVisitor(ParserService.CurrentProjectContent,
                                                                ParserService.GetParseInformation(content.PrimaryFileName));
                v.VisitCompilationUnit(p.CompilationUnit, null);
                using (SpecialNodesInserter.Install(specials, vbv)) {
                    vbv.VisitCompilationUnit(p.CompilationUnit, null);
                }

                FileService.NewFile("Generated.vb", vbv.Text);
            }
        }
Beispiel #3
0
        /// <summary>
        /// 获得所有的regions区域信息,textspan都是基于(0,0)开始的
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        public static List <TextSpan> GetAllRegions(string content)
        {
            List <TextSpan> allRegions = new List <TextSpan>();

            using (IParser parser = ParserFactory.CreateParser(SupportedLanguage.CSharp, new StringReader(content)))
            {
                parser.ParseMethodBodies = false;
                parser.Parse();

                List <ISpecial> currentSpecials = parser.Lexer.SpecialTracker.CurrentSpecials;
                TextSpan        textSpan        = new TextSpan();
                //使用栈来寻找可能嵌套的region
                Stack <int> stack = new Stack <int>();
                foreach (ISpecial currentSpecial in currentSpecials)
                {
                    if (currentSpecial is PreprocessingDirective)
                    {
                        PreprocessingDirective region = currentSpecial as PreprocessingDirective;
                        if (region.Cmd == "#region")
                        {
                            stack.Push(region.StartPosition.Line - 1);
                            //textSpan.iStartLine = region.StartPosition.Line - 1;
                        }
                        if (region.Cmd == "#endregion")
                        {
                            textSpan.iStartLine = stack.Pop();
                            textSpan.iEndLine   = region.StartPosition.Line - 1;
                            allRegions.Add(textSpan);
                        }
                    }
                }
            }
            return(allRegions);
        }
 public void AddPreprocessingDirective(PreprocessingDirective directive)
 {
     if (directive == null)
     {
         throw new ArgumentNullException("directive");
     }
     currentSpecials.Add(directive);
 }
 public object Visit(PreprocessingDirective special, object data)
 {
     if (!specialHasBeenHandled(special))
     {
         formatter.PrintPreprocessingDirective(special, ForceWriteInPreviousLine);
         considerSpecialAsHandled(special);
     }
     return(data);
 }
 public virtual void PrintPreprocessingDirective(PreprocessingDirective directive, bool forceWriteInPreviousBlock)
 {
     if (string.IsNullOrEmpty(directive.Arg))
     {
         WriteLineInPreviousLine(directive.Cmd, forceWriteInPreviousBlock);
     }
     else
     {
         WriteLineInPreviousLine(directive.Cmd + " " + directive.Arg, forceWriteInPreviousBlock);
     }
 }
        protected override void ConvertAst(CompilationUnit compilationUnit, List <ISpecial> specials, FileProjectItem sourceItem)
        {
            PreprocessingDirective.CSharpToVB(specials);
            IProjectContent             pc      = ParserService.GetProjectContent(sourceItem.Project) ?? ParserService.CurrentProjectContent;
            CSharpToVBNetConvertVisitor visitor = new CSharpToVBNetConvertVisitor(pc, ParserService.GetParseInformation(sourceItem.FileName));

            visitor.RootNamespaceToRemove     = sourceItem.Project.RootNamespace;
            visitor.DefaultImportsToRemove    = defaultImports;
            visitor.StartupObjectToMakePublic = startupObject;
            compilationUnit.AcceptVisitor(visitor, null);
        }
Beispiel #8
0
 public override void PrintPreprocessingDirective(PreprocessingDirective directive, bool forceWriteInPreviousBlock)
 {
     if (IsInMemberBody
         && (string.Equals(directive.Cmd, "#Region", StringComparison.InvariantCultureIgnoreCase)
             || string.Equals(directive.Cmd, "#End", StringComparison.InvariantCultureIgnoreCase)
             && directive.Arg.ToLowerInvariant().StartsWith("region")))
     {
         WriteLineInPreviousLine("'" + directive.Cmd + " " + directive.Arg, forceWriteInPreviousBlock);
     } else {
         base.PrintPreprocessingDirective(directive, forceWriteInPreviousBlock);
     }
 }
Beispiel #9
0
 object ISpecialVisitor.Visit(PreprocessingDirective special, object data)
 {
     if (string.IsNullOrEmpty(special.Arg))
     {
         WriteSpecialText(false, "{0}", special.Cmd);
     }
     else
     {
         WriteSpecialText(false, "{0} {1}", special.Cmd, special.Arg);
     }
     return(null);
 }
Beispiel #10
0
        protected override void ConvertAst(CompilationUnit compilationUnit, List <ISpecial> specials, FileProjectItem sourceItem)
        {
            PreprocessingDirective.VBToCSharp(specials);
            CompilableProject project = (CompilableProject)sourceItem.Project;

            RemoveWindowsFormsSpecificCode(compilationUnit, specials, project.OutputType == OutputType.WinExe);

            IProjectContent             pc      = ParserService.GetProjectContent(sourceItem.Project) ?? ParserService.CurrentProjectContent;
            VBNetToCSharpConvertVisitor visitor = new VBNetToCSharpConvertVisitorWithMyFormsSupport(pc, ParserService.GetParseInformation(sourceItem.FileName), sourceItem.Project.RootNamespace);

            compilationUnit.AcceptVisitor(visitor, null);
        }
        public string VBToCSharp(string input, out string errors)
        {
            INode node = Parse(SupportedLanguage.VBNet, input, out errors);

            if (node == null)
            {
                return(null);
            }
            // apply conversion logic:
            compilationUnit.AcceptVisitor(
                new VBNetToCSharpConvertVisitor(project, parseInfo),
                null);
            PreprocessingDirective.VBToCSharp(specials);
            return(CreateCode(UnpackExpression(node), new CSharpOutputVisitor()));
        }
Beispiel #12
0
        private void Generate(SupportedLanguage language, TextReader inputstream, OutputClass output)
        {
            IParser parser = ParserFactory.CreateParser(language, inputstream);

            parser.Parse();
            if (parser.Errors.Count > 0)
            {
                new ExceptionDialog(null, "Error Parsing Input Code").ShowDialog();
            }
            else if (output.CodeDomProvider != null)
            {
                CodeDomVisitor visitor = new CodeDomVisitor();
                visitor.VisitCompilationUnit(parser.CompilationUnit, null);
                for (int i = visitor.codeCompileUnit.Namespaces.Count - 1; i >= 0; i--)
                {
                    if (visitor.codeCompileUnit.Namespaces[i].Types.Count == 0)
                    {
                        visitor.codeCompileUnit.Namespaces.RemoveAt(i);
                    }
                }
                CodeGeneratorOptions options = new CodeGeneratorOptions();
                options.BlankLinesBetweenMembers = true;
                StringWriter writer = new StringWriter();
                output.CodeDomProvider.GenerateCodeFromCompileUnit(visitor.codeCompileUnit, writer, options);
                this.scintillaOutput.Text = writer.ToString();
                writer.Close();
            }
            else
            {
                AbstractAstTransformer transformer     = output.CreateTransformer();
                List <ISpecial>        currentSpecials = parser.Lexer.SpecialTracker.CurrentSpecials;
                if ((language == SupportedLanguage.CSharp) && (transformer is ToVBNetConvertVisitor))
                {
                    PreprocessingDirective.CSharpToVB(currentSpecials);
                }
                else if ((language == SupportedLanguage.VBNet) && (transformer is ToCSharpConvertVisitor))
                {
                    PreprocessingDirective.VBToCSharp(currentSpecials);
                }
                parser.CompilationUnit.AcceptVisitor(transformer, null);
                IOutputAstVisitor outputVisitor = output.CreatePrettyPrinter();
                using (SpecialNodesInserter.Install(currentSpecials, outputVisitor))
                {
                    outputVisitor.VisitCompilationUnit(parser.CompilationUnit, null);
                }
                this.scintillaOutput.Text = outputVisitor.Text;
            }
        }
Beispiel #13
0
        public string CSharpToVB(string input, out string errors)
        {
            INode node = Parse(SupportedLanguage.CSharp, input, out errors);

            if (node == null)
            {
                return(null);
            }
            // apply conversion logic:
            var visitor = new CSharpToVBNetConvertVisitor(project, parseInfo);

            visitor.DefaultImportsToRemove = DefaultImportsToRemove;
            compilationUnit.AcceptVisitor(visitor, null);
            PreprocessingDirective.CSharpToVB(specials);
            return(CreateCode(UnpackExpression(node), new VBNetOutputVisitor()));
        }
		public override void PrintPreprocessingDirective(PreprocessingDirective directive, bool forceWriteInPreviousBlock)
		{
			if (IsInMemberBody
			    && (string.Equals(directive.Cmd, "#Region", StringComparison.InvariantCultureIgnoreCase)
			        || string.Equals(directive.Cmd, "#End", StringComparison.InvariantCultureIgnoreCase)
			        && directive.Arg.StartsWith("Region", StringComparison.InvariantCultureIgnoreCase)))
			{
				WriteLineInPreviousLine("'" + directive.Cmd + " " + directive.Arg, forceWriteInPreviousBlock);
			} else if (!directive.Expression.IsNull) {
				VBNetOutputVisitor visitor = new VBNetOutputVisitor();
				directive.Expression.AcceptVisitor(visitor, null);
				WriteLineInPreviousLine(directive.Cmd + " " + visitor.Text + " Then", forceWriteInPreviousBlock);
			} else {
				base.PrintPreprocessingDirective(directive, forceWriteInPreviousBlock);
			}
		}
Beispiel #15
0
 void RemoveWindowsFormsSpecificCode(CompilationUnit compilationUnit, List <ISpecial> specials, bool keepCode)
 {
     for (int i = 0; i < specials.Count; i++)
     {
         PreprocessingDirective ppd = specials[i] as PreprocessingDirective;
         if (ppd != null && ppd.Cmd == "#if")
         {
             if (ppd.Arg == "_MyType = \"WindowsForms\"")
             {
                 int depth = 1;
                 for (int j = i + 1; j < specials.Count; j++)
                 {
                     ppd = specials[j] as PreprocessingDirective;
                     if (ppd != null)
                     {
                         if (ppd.Cmd == "#if")
                         {
                             depth++;
                         }
                         else if (ppd.Cmd == "#endif")
                         {
                             depth--;
                             if (depth == 0)
                             {
                                 if (keepCode)
                                 {
                                     // keep code, remove only the ifdef
                                     specials.RemoveAt(j);
                                     specials.RemoveAt(i);
                                 }
                                 else
                                 {
                                     // remove ifdef including the code
                                     compilationUnit.AcceptVisitor(new RemoveMembersInRangeVisitor(
                                                                       DomRegion.FromLocation(specials[i].StartPosition, specials[j].EndPosition)), null);
                                     specials.RemoveRange(i, j - i + 1);
                                 }
                                 i--;
                                 break;
                             }
                         }
                     }
                 }
             }
         }
     }
 }
Beispiel #16
0
 public virtual void PrintPreprocessingDirective(PreprocessingDirective directive, bool forceWriteInPreviousBlock)
 {
     if (!directive.Expression.IsNull)
     {
         CSharpOutputVisitor visitor = new CSharpOutputVisitor();
         directive.Expression.AcceptVisitor(visitor, null);
         WriteLineInPreviousLine(directive.Cmd + " " + visitor.Text, forceWriteInPreviousBlock);
     }
     else if (string.IsNullOrEmpty(directive.Arg))
     {
         WriteLineInPreviousLine(directive.Cmd, forceWriteInPreviousBlock);
     }
     else
     {
         WriteLineInPreviousLine(directive.Cmd + " " + directive.Arg, forceWriteInPreviousBlock);
     }
 }
        protected override void ConvertAst(CompilationUnit compilationUnit, List <ISpecial> specials, FileProjectItem sourceItem)
        {
            PreprocessingDirective.VBToCSharp(specials);
            CompilableProject project = (CompilableProject)sourceItem.Project;

            RemoveWindowsFormsSpecificCode(compilationUnit, specials, project.OutputType == OutputType.WinExe);

            IProjectContent             pc      = ParserService.GetProjectContent(sourceItem.Project) ?? ParserService.CurrentProjectContent;
            VBNetToCSharpConvertVisitor visitor = new VBNetToCSharpConvertVisitorWithMyFormsSupport(pc, ParserService.GetParseInformation(sourceItem.FileName), sourceItem.Project.RootNamespace);

            // set project options
            visitor.OptionInfer = (project.GetEvaluatedProperty("OptionInfer") ?? "Off")
                                  .Equals("On", StringComparison.OrdinalIgnoreCase);
            visitor.OptionStrict = (project.GetEvaluatedProperty("OptionStrict") ?? "Off")
                                   .Equals("On", StringComparison.OrdinalIgnoreCase);

            compilationUnit.AcceptVisitor(visitor, null);
        }
Beispiel #18
0
        void TestProgramCS2VB(string programCS, string programVB)
        {
            IParser parser = ParserFactory.CreateParser(SupportedLanguage.CSharp, new StringReader(programCS));

            parser.Parse();
            Assert.AreEqual("", parser.Errors.ErrorOutput);
            VBNetOutputVisitor outputVisitor = new VBNetOutputVisitor();
            List <ISpecial>    specials      = parser.Lexer.SpecialTracker.RetrieveSpecials();

            PreprocessingDirective.CSharpToVB(specials);
            outputVisitor.Options.IndentationChar = ' ';
            outputVisitor.Options.IndentSize      = 2;
            using (SpecialNodesInserter.Install(specials, outputVisitor)) {
                outputVisitor.VisitCompilationUnit(parser.CompilationUnit, null);
            }
            Assert.AreEqual("", outputVisitor.Errors.ErrorOutput);
            Assert.AreEqual(programVB.Replace("\r", ""), outputVisitor.Text.TrimEnd().Replace("\r", ""));
            parser.Dispose();
        }
Beispiel #19
0
        public static Module ParseModule(CompileUnit cu, TextReader input, ConverterSettings settings, out IList <ISpecial> specials)
        {
            if (cu == null)
            {
                throw new ArgumentNullException("cu");
            }
            if (input == null)
            {
                throw new ArgumentNullException("input");
            }
            if (settings == null)
            {
                throw new ArgumentNullException("settings");
            }
            IParser   parser    = ParserFactory.CreateParser(settings.IsVisualBasic ? SupportedLanguage.VBNet : SupportedLanguage.CSharp, input);
            ErrorTrap errorTrap = new ErrorTrap(settings);

            parser.Errors.SemErr = errorTrap.DefaultCodeError;
            parser.Errors.SynErr = errorTrap.DefaultCodeError;
            parser.Errors.Error  = errorTrap.DefaultMsgError;
            parser.Parse();
            specials = parser.Lexer.SpecialTracker.CurrentSpecials;
            if (settings.IsVisualBasic)
            {
                PreprocessingDirective.VBToCSharp(specials);
            }
            // abort when file has errors
            if (errorTrap.count > 0)
            {
                return(null);
            }
            Module m = Converter.Convert(parser.CompilationUnit, settings);

            if (m != null && cu != null)
            {
                cu.Modules.Add(m);
                if (settings.RemoveRedundantTypeReferences)
                {
                    cu.Accept(new RemoveRedundantTypeReferencesVisitor());
                }
            }
            return(m);
        }
Beispiel #20
0
 public override void PrintPreprocessingDirective(PreprocessingDirective directive, bool forceWriteInPreviousBlock)
 {
     if (IsInMemberBody &&
         (string.Equals(directive.Cmd, "#Region", StringComparison.InvariantCultureIgnoreCase) ||
          string.Equals(directive.Cmd, "#End", StringComparison.InvariantCultureIgnoreCase) &&
          directive.Arg.StartsWith("Region", StringComparison.InvariantCultureIgnoreCase)))
     {
         WriteLineInPreviousLine("'" + directive.Cmd + " " + directive.Arg, forceWriteInPreviousBlock);
     }
     else if (!directive.Expression.IsNull)
     {
         VBNetOutputVisitor visitor = new VBNetOutputVisitor();
         directive.Expression.AcceptVisitor(visitor, null);
         WriteLineInPreviousLine(directive.Cmd + " " + visitor.Text + " Then", forceWriteInPreviousBlock);
     }
     else
     {
         base.PrintPreprocessingDirective(directive, forceWriteInPreviousBlock);
     }
 }
        private static string ConvertVBCodeToCSharp(string Code)
        {
            IParser p = ParserFactory.CreateParser(SupportedLanguage.VBNet, new StringReader(Code));

            p.Parse();
            if (p.Errors.Count > 0)
            {
                return(Code);
            }
            NRefactory.PrettyPrinter.CSharpOutputVisitor output = new NRefactory.PrettyPrinter.CSharpOutputVisitor();
            List <ISpecial> specials = p.Lexer.SpecialTracker.CurrentSpecials;

            PreprocessingDirective.VBToCSharp(specials);
            p.CompilationUnit.AcceptVisitor(new NRefactory.Visitors.VBNetConstructsConvertVisitor(), null);
            p.CompilationUnit.AcceptVisitor(new NRefactory.Visitors.ToCSharpConvertVisitor(), null);

            using (NRefactory.PrettyPrinter.SpecialNodesInserter.Install(specials, output))
            {
                output.VisitCompilationUnit(p.CompilationUnit, null);
            }
            return(output.Text);
        }
        public void TestProgram(string input, string expectedOutput)
        {
            IParser parser = ParserFactory.CreateParser(SupportedLanguage.CSharp, new StringReader(input));

            parser.Parse();
            Assert.AreEqual("", parser.Errors.ErrorOutput);
            var specials = parser.Lexer.SpecialTracker.RetrieveSpecials();

            PreprocessingDirective.CSharpToVB(specials);
            parser.CompilationUnit.AcceptVisitor(new CSharpConstructsConvertVisitor(), null);
            parser.CompilationUnit.AcceptVisitor(new ToVBNetConvertVisitor(), null);
            VBNetOutputVisitor outputVisitor = new VBNetOutputVisitor();

            outputVisitor.Options.IndentationChar     = ' ';
            outputVisitor.Options.IndentSize          = 2;
            outputVisitor.Options.OutputByValModifier = true;
            using (SpecialNodesInserter.Install(specials, outputVisitor)) {
                outputVisitor.VisitCompilationUnit(parser.CompilationUnit, null);
            }
            Assert.AreEqual("", outputVisitor.Errors.ErrorOutput);
            Assert.AreEqual(expectedOutput.Replace("\r", ""), outputVisitor.Text.Replace("\r", ""));
        }
        static List <HashSet <string> > GetUsedDefineCombinations(ICSharpCode.NRefactory.IParser parser)
        {
            List <HashSet <string> > result = new List <HashSet <string> > ();

            foreach (ISpecial special in parser.Lexer.SpecialTracker.CurrentSpecials)
            {
                PreprocessingDirective directive = special as PreprocessingDirective;
                if (directive == null || (directive.Cmd != "#if" && directive.Cmd != "#elif"))
                {
                    continue;
                }

                ExpressionVisitor visitor = new ExpressionVisitor();
                directive.Expression.AcceptVisitor(visitor, null);
                ICSharpCode.NRefactory.Parser.CSharp.ConditionalCompilation cond = new ICSharpCode.NRefactory.Parser.CSharp.ConditionalCompilation();
                bool nothingDefined = cond.Evaluate(directive.Expression);
                foreach (var combination in GetAllCombinations(visitor.Identifiers))
                {
                    cond = new ICSharpCode.NRefactory.Parser.CSharp.ConditionalCompilation();
                    HashSet <string> defines = new HashSet <string> ();
                    foreach (string usedIdentifier in combination)
                    {
                        cond.Define(usedIdentifier);
                        defines.Add(usedIdentifier);
                        bool curDefineStatus = cond.Evaluate(directive.Expression);
                        if (curDefineStatus != nothingDefined)
                        {
                            result.Add(defines);
                            goto next;
                        }
                    }
                }
next:
                ;
            }
            return(result);
        }
Beispiel #24
0
        void VB2CS(string input, string expectedOutput)
        {
            SnippetParser parser = new SnippetParser(SupportedLanguage.VBNet);
            INode         node   = parser.Parse(input);

            // parser.Errors.ErrorOutput contains syntax errors, if any
            Assert.IsNotNull(node);
            Assert.AreEqual("", parser.Errors.ErrorOutput);
            // parser.Specials is the list of comments, preprocessor directives etc.
            PreprocessingDirective.VBToCSharp(parser.Specials);
            // Convert VB.NET constructs to C#:
            node.AcceptVisitor(new VBNetConstructsConvertVisitor(), null);
            node.AcceptVisitor(new ToCSharpConvertVisitor(), null);

            CSharpOutputVisitor output = new CSharpOutputVisitor();

            using (SpecialNodesInserter.Install(parser.Specials, output)) {
                node.AcceptVisitor(output, null);
            }
            // output.Errors.ErrorOutput contains conversion errors/warnings, if any
            // output.Text contains the converted code
            Assert.AreEqual("", output.Errors.ErrorOutput);
            Assert.AreEqual(expectedOutput, output.Text);
        }
		public virtual void PrintPreprocessingDirective(PreprocessingDirective directive, bool forceWriteInPreviousBlock)
		{
			if (!directive.Expression.IsNull) {
				CSharpOutputVisitor visitor = new CSharpOutputVisitor();
				directive.Expression.AcceptVisitor(visitor, null);
				WriteLineInPreviousLine(directive.Cmd + " " + visitor.Text, forceWriteInPreviousBlock);
			} else if (string.IsNullOrEmpty(directive.Arg))
				WriteLineInPreviousLine(directive.Cmd, forceWriteInPreviousBlock);
			else
				WriteLineInPreviousLine(directive.Cmd + " " + directive.Arg, forceWriteInPreviousBlock);
		}
 protected override void ConvertAst(CompilationUnit compilationUnit, List <ISpecial> specials)
 {
     PreprocessingDirective.VBToCSharp(specials);
     compilationUnit.AcceptVisitor(new VBNetToCSharpConvertVisitor(), null);
 }
 public object Visit(PreprocessingDirective special, object data)
 {
     formatter.PrintPreprocessingDirective(special, ForceWriteInPreviousLine);
     return(data);
 }
		public virtual void PrintPreprocessingDirective(PreprocessingDirective directive, bool forceWriteInPreviousBlock)
		{
			if (string.IsNullOrEmpty(directive.Arg))
				WriteLineInPreviousLine(directive.Cmd, forceWriteInPreviousBlock);
			else
				WriteLineInPreviousLine(directive.Cmd + " " + directive.Arg, forceWriteInPreviousBlock);
		}
Beispiel #29
0
		public void AddPreprocessingDirective(PreprocessingDirective directive)
		{
			if (directive == null)
				throw new ArgumentNullException("directive");
			currentSpecials.Add(directive);
		}
		PreprocessingDirective ReadPreProcessingDirectiveInternal(bool parseIfExpression, bool parseElifExpression)
		{
			Location start = new Location(Col - 1, Line);
			
			// skip spaces between # and the directive
			PPWhitespace();
			
			bool canBeKeyword;
			string directive = ReadIdent('#', out canBeKeyword);
			
			PPWhitespace();
			if (parseIfExpression && directive == "#if" || parseElifExpression && directive == "#elif") {
				recordedText.Length = 0;
				recordRead = true;
				Ast.Expression expr = PPExpression();
				string arg = recordedText.ToString ();
				recordRead = false;
				
				Location endLocation = new Location(Col, Line);
				int c = ReaderRead();
				if (c >= 0 && !HandleLineEnd((char)c)) {
					if (c == '/' && ReaderRead() == '/') {
						// comment to end of line
					} else {
						errors.Error(Col, Line, "Expected end of line");
					}
					SkipToEndOfLine(); // skip comment
				}
				var preprocessingDirective = new PreprocessingDirective(directive, arg, start, endLocation);
				preprocessingDirective.Expression = expr;
				preprocessingDirective.LastLineEnd = lastLineEnd;
				return preprocessingDirective;
			} else 
			{
				Location endLocation = new Location(Col, Line);
				string arg = ReadToEndOfLine();
				endLocation.Column += arg.Length;
				int pos = arg.IndexOf("//");
				if (pos >= 0)
					arg = arg.Substring(0, pos);
				arg = arg.Trim();
				var preprocessingDirective = new PreprocessingDirective(directive, arg, start, endLocation);
				preprocessingDirective.LastLineEnd = lastLineEnd ;
				return preprocessingDirective;
			}
		}
		public object Visit(PreprocessingDirective special, object data)
		{
			formatter.PrintPreprocessingDirective(special, ForceWriteInPreviousLine);
			return data;
		}