/// <summary> /// Extracts the body of the given preprocessor directive symbol, parses it, and returns the parsed expression. /// </summary> /// <param name="parser">The C# parser.</param> /// <param name="sourceCode">The source code containing the preprocessor directive symbol.</param> /// <param name="preprocessorSymbol">The preprocessor directive symbol.</param> /// <param name="startIndex">The index of the start of the expression body within the text string.</param> /// <returns>Returns the expression.</returns> internal static Expression GetConditionalPreprocessorBodyExpression( CsParser parser, SourceCode sourceCode, Symbol preprocessorSymbol, int startIndex) { Param.AssertNotNull(parser, "parser"); Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); Debug.Assert(preprocessorSymbol.SymbolType == SymbolType.PreprocessorDirective, "The symbol is not a preprocessor directive."); string text = preprocessorSymbol.Text.Substring(startIndex, preprocessorSymbol.Text.Length - startIndex).Trim(); if (text.Length > 0) { using (StringReader reader = new StringReader(text)) { // Extract the symbols within this text. CodeLexer lexer = new CodeLexer(parser, sourceCode, new CodeReader(reader)); List<Symbol> symbolList = lexer.GetSymbols(sourceCode, null); SymbolManager directiveSymbols = new SymbolManager(symbolList); CodeParser preprocessorBodyParser = new CodeParser(parser, directiveSymbols); // Parse these symbols to create the body expression. return preprocessorBodyParser.GetNextConditionalPreprocessorExpression(sourceCode); } } // The directive has no body. return null; }
/// <summary> /// Creates an operator token from the given symbol. /// </summary> /// <param name="symbol">The symbol to convert.</param> /// <param name="parentReference">The parent code part.</param> /// <param name="generated">Indicates whether the symbol lies within a generated code block.</param> /// <returns>Returns the operator symbol.</returns> private static OperatorSymbol CreateOperatorToken(Symbol symbol, Reference<ICodePart> parentReference, bool generated) { Param.AssertNotNull(symbol, "symbol"); Param.AssertNotNull(parentReference, "parentReference"); Param.Ignore(generated); // Get the type of the operator. OperatorType type; OperatorCategory category; if (!GetOperatorType(symbol, out type, out category)) { // This should never happen unless there is a bug in the code. Debug.Fail("Unexpected operator type"); throw new InvalidOperationException(); } // Create and return the operator. return new OperatorSymbol(symbol.Text, category, type, symbol.Location, parentReference, generated); }
private CsToken ConvertSymbol(Symbol symbol, CsTokenType tokenType) { if (symbol.SymbolType == SymbolType.WhiteSpace) { return new Whitespace(symbol.Text, symbol.Location, this.symbols.Generated); } if (symbol.SymbolType == SymbolType.Number) { return new Microsoft.StyleCop.CSharp.Number(symbol.Text, symbol.Location, this.symbols.Generated); } if (symbol.SymbolType == SymbolType.PreprocessorDirective) { return this.GetPreprocessorDirectiveToken(symbol, this.symbols.Generated); } return new CsToken(symbol.Text, tokenType, CsTokenClass.Token, symbol.Location, this.symbols.Generated); }
/// <summary> /// Gets the next conditional compilation directive from the code. /// </summary> /// <param name="preprocessorSymbol">The symbol representing the directive.</param> /// <param name="type">The type of the conditional compilation directive.</param> /// <param name="startIndex">The start index of the body of the directive.</param> /// <param name="parent">The parent code part.</param> /// <param name="generated">Indicates whether the directive lies within a block of generated code.</param> /// <returns>Returns the directive.</returns> private ConditionalCompilationDirective GetConditionalCompilationDirective( Symbol preprocessorSymbol, ConditionalCompilationDirectiveType type, int startIndex, Reference<ICodePart> parent, bool generated) { Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.Ignore(type); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); Param.AssertNotNull(parent, "parent"); Param.Ignore(generated); Expression body = null; // Extract the body of the directive if necessary. if (type != ConditionalCompilationDirectiveType.Endif && startIndex < preprocessorSymbol.Text.Length) { body = CodeParser.GetConditionalPreprocessorBodyExpression( this.parser, this.document.SourceCode, preprocessorSymbol, startIndex); } // Create and return the directive. return new ConditionalCompilationDirective( preprocessorSymbol.Text, type, body, preprocessorSymbol.Location, parent, generated); }
/// <summary> /// Reads, creates, and moves past a symbol. /// </summary> /// <param name="text">The symbol text.</param> /// <param name="type">The type of the symbol.</param> /// <returns>Returns the symbol.</returns> private Symbol CreateAndMovePastSymbol(string text, SymbolType type) { Param.AssertValidString(text, "text"); Param.Ignore(type); this.codeReader.ReadNext(); Symbol symbol = new Symbol(text, type, CodeLocationFromMarker(this.marker)); ++this.marker.Index; ++this.marker.IndexOnLine; return symbol; }
/// <summary> /// Gets the next Xml header line from the code. /// </summary> /// <param name="text">The buffer in which to store the text.</param> /// <returns>Returns the Xml header line.</returns> private Symbol GetXmlHeaderLine(StringBuilder text) { Param.AssertNotNull(text, "text"); // Find the end of the current line. this.AdvanceToEndOfLine(text); // Create the code location. CodeLocation location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, this.marker.LineNumber); // Create the symbol. Symbol symbol = new Symbol(text.ToString(), SymbolType.XmlHeaderLine, location); // Update the marker. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; // Return the symbol. return symbol; }
/// <summary> /// Gets an undefine preprocessor directive from the code. /// </summary> /// <param name="sourceCode">The source code being parsed.</param> /// <param name="preprocessorSymbol">The preprocessor symbol being parsed.</param> /// <param name="startIndex">The start index within the symbols.</param> private void GetUndefinePreprocessorDirective(SourceCode sourceCode, Symbol preprocessorSymbol, int startIndex) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); // Get the body of the undefine directive. LiteralExpression body = CodeParser.GetConditionalPreprocessorBodyExpression( this.parser, sourceCode, preprocessorSymbol, startIndex) as LiteralExpression; if (body == null) { throw new SyntaxException(sourceCode, preprocessorSymbol.LineNumber); } // Create the undefines list if necessary. if (this.undefines == null) { this.undefines = new Dictionary<string, string>(); } // Add the item to the list. if (!this.undefines.ContainsKey(body.Text)) { this.undefines.Add(body.Text, body.Text); } // Remove the item from the defines list if it exists. if (this.defines != null) { this.defines.Remove(body.Text); } }
/// <summary> /// Gets the next preprocessor directive keyword. /// </summary> /// <param name="sourceCode">The source code.</param> /// <param name="configuration">The active configuration.</param> /// <param name="evaluate">Indicates whether to evaluate the preprocessor symbol if it is a conditional /// directive.</param> /// <returns>Returns the next preprocessor directive keyword.</returns> private Symbol GetPreprocessorDirectiveSymbol( SourceCode sourceCode, Configuration configuration, bool evaluate) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.Ignore(configuration); Param.Ignore(evaluate); // Find the end of the current line. StringBuilder text = new StringBuilder(); this.AdvanceToEndOfLine(text); if (text.Length == 1) { throw new SyntaxException(sourceCode, 1, Strings.UnexpectedEndOfFile); } // Create the code location. CodeLocation location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, this.marker.LineNumber); // Create the symbol. Symbol symbol = new Symbol(text.ToString(), SymbolType.PreprocessorDirective, location); // Update the marker. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; if (evaluate && configuration != null) { // Check the type of the symbol. If this is a conditional preprocessor symbol which resolves to false, // then we need to advance past all of the code which is not in scope. this.CheckForConditionalCompilationDirective(sourceCode, symbol, configuration); } // Return the symbol. return symbol; }
private Symbol GetOperatorSymbol(char character) { Param.Ignore(character); SymbolType type = SymbolType.Other; StringBuilder text = new StringBuilder(); if (character == '.') { text.Append("."); type = SymbolType.Dot; this.codeReader.ReadNext(); } else if (character == '~') { text.Append("~"); type = SymbolType.Tilde; this.codeReader.ReadNext(); } else if (character == '+') { text.Append("+"); type = SymbolType.Plus; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '+') { text.Append("+"); type = SymbolType.Increment; this.codeReader.ReadNext(); } else if (character == '=') { text.Append("="); type = SymbolType.PlusEquals; this.codeReader.ReadNext(); } } else if (character == '-') { text.Append("-"); type = SymbolType.Minus; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '-') { text.Append("-"); type = SymbolType.Decrement; this.codeReader.ReadNext(); } else if (character == '=') { text.Append("="); type = SymbolType.MinusEquals; this.codeReader.ReadNext(); } else if (character == '>') { text.Append(">"); type = SymbolType.Pointer; this.codeReader.ReadNext(); } } else if (character == '*') { text.Append("*"); type = SymbolType.Multiplication; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("*"); type = SymbolType.MultiplicationEquals; this.codeReader.ReadNext(); } } else if (character == '/') { text.Append("/"); type = SymbolType.Division; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.DivisionEquals; this.codeReader.ReadNext(); } } else if (character == '|') { text.Append("|"); type = SymbolType.LogicalOr; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.OrEquals; this.codeReader.ReadNext(); } else if (character == '|') { text.Append("|"); type = SymbolType.ConditionalOr; this.codeReader.ReadNext(); } } else if (character == '&') { text.Append("&"); type = SymbolType.LogicalAnd; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.AndEquals; this.codeReader.ReadNext(); } else if (character == '&') { text.Append("&"); type = SymbolType.ConditionalAnd; this.codeReader.ReadNext(); } } else if (character == '^') { text.Append("^"); type = SymbolType.LogicalXor; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.XorEquals; this.codeReader.ReadNext(); } } else if (character == '!') { text.Append("!"); type = SymbolType.Not; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.NotEquals; this.codeReader.ReadNext(); } } else if (character == '%') { text.Append("%"); type = SymbolType.Mod; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.ModEquals; this.codeReader.ReadNext(); } } else if (character == '=') { text.Append("="); type = SymbolType.Equals; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.ConditionalEquals; this.codeReader.ReadNext(); } else if (character == '>') { text.Append(">"); type = SymbolType.Lambda; this.codeReader.ReadNext(); } } else if (character == '<') { text.Append("<"); type = SymbolType.LessThan; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.LessThanOrEquals; this.codeReader.ReadNext(); } else if (character == '<') { text.Append("<"); type = SymbolType.LeftShift; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.LeftShiftEquals; this.codeReader.ReadNext(); } } } else if (character == '>') { text.Append(">"); type = SymbolType.GreaterThan; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.GreaterThanOrEquals; this.codeReader.ReadNext(); } // Note: The right-shift symbol confuses the parsing of generics. // If there are two greater-thans in a row then this may be a right-shift // symbol, but we cannot create it as such right now because it may also // be a couple of closing generic symbols in a row. This will have to be // parsed out in the code. If this is a right-shift-equals then this will // be created as three separate symbols, two greater-thans and then an // equals. Later on we will recombine these. } else if (character == '?') { text.Append("?"); type = SymbolType.QuestionMark; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '?') { text.Append("?"); type = SymbolType.NullCoalescingSymbol; this.codeReader.ReadNext(); } } else if (character == ':') { text.Append(":"); type = SymbolType.Colon; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == ':') { text.Append(":"); type = SymbolType.QualifiedAlias; this.codeReader.ReadNext(); } } // Make sure we have a symbol now. if (text == null || text.Length == 0) { throw new SyntaxException(this.source, this.marker.LineNumber); } // Create the code location. CodeLocation location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, this.marker.LineNumber); // Create the token. Symbol symbol = new Symbol(text.ToString(), type, location); // Update the marker. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; // Return the symbol. return symbol; }
private static bool GetOperatorType(Symbol symbol, out OperatorType type, out OperatorCategory category) { bool flag = true; switch (symbol.SymbolType) { case SymbolType.Equals: type = OperatorType.Equals; category = OperatorCategory.Assignment; return flag; case SymbolType.ConditionalEquals: type = OperatorType.ConditionalEquals; category = OperatorCategory.Relational; return flag; case SymbolType.Plus: type = OperatorType.Plus; category = OperatorCategory.Arithmetic; return flag; case SymbolType.PlusEquals: type = OperatorType.PlusEquals; category = OperatorCategory.Assignment; return flag; case SymbolType.Minus: type = OperatorType.Minus; category = OperatorCategory.Arithmetic; return flag; case SymbolType.MinusEquals: type = OperatorType.MinusEquals; category = OperatorCategory.Assignment; return flag; case SymbolType.Multiplication: type = OperatorType.Multiplication; category = OperatorCategory.Arithmetic; return flag; case SymbolType.MultiplicationEquals: type = OperatorType.MultiplicationEquals; category = OperatorCategory.Assignment; return flag; case SymbolType.Division: type = OperatorType.Division; category = OperatorCategory.Arithmetic; return flag; case SymbolType.DivisionEquals: type = OperatorType.DivisionEquals; category = OperatorCategory.Assignment; return flag; case SymbolType.LessThan: type = OperatorType.LessThan; category = OperatorCategory.Relational; return flag; case SymbolType.LessThanOrEquals: type = OperatorType.LessThanOrEquals; category = OperatorCategory.Relational; return flag; case SymbolType.LeftShift: type = OperatorType.LeftShift; category = OperatorCategory.Shift; return flag; case SymbolType.LeftShiftEquals: type = OperatorType.LeftShiftEquals; category = OperatorCategory.Assignment; return flag; case SymbolType.GreaterThan: type = OperatorType.GreaterThan; category = OperatorCategory.Relational; return flag; case SymbolType.GreaterThanOrEquals: type = OperatorType.GreaterThanOrEquals; category = OperatorCategory.Relational; return flag; case SymbolType.RightShift: type = OperatorType.RightShift; category = OperatorCategory.Shift; return flag; case SymbolType.RightShiftEquals: type = OperatorType.RightShiftEquals; category = OperatorCategory.Assignment; return flag; case SymbolType.Increment: type = OperatorType.Increment; category = OperatorCategory.IncrementDecrement; return flag; case SymbolType.Decrement: type = OperatorType.Decrement; category = OperatorCategory.IncrementDecrement; return flag; case SymbolType.LogicalAnd: type = OperatorType.LogicalAnd; category = OperatorCategory.Logical; return flag; case SymbolType.AndEquals: type = OperatorType.AndEquals; category = OperatorCategory.Assignment; return flag; case SymbolType.ConditionalAnd: type = OperatorType.ConditionalAnd; category = OperatorCategory.Logical; return flag; case SymbolType.LogicalOr: type = OperatorType.LogicalOr; category = OperatorCategory.Logical; return flag; case SymbolType.OrEquals: type = OperatorType.OrEquals; category = OperatorCategory.Assignment; return flag; case SymbolType.ConditionalOr: type = OperatorType.ConditionalOr; category = OperatorCategory.Logical; return flag; case SymbolType.LogicalXor: type = OperatorType.LogicalXor; category = OperatorCategory.Logical; return flag; case SymbolType.XorEquals: type = OperatorType.XorEquals; category = OperatorCategory.Assignment; return flag; case SymbolType.Not: type = OperatorType.Not; category = OperatorCategory.Unary; return flag; case SymbolType.NotEquals: type = OperatorType.NotEquals; category = OperatorCategory.Relational; return flag; case SymbolType.Mod: type = OperatorType.Mod; category = OperatorCategory.Arithmetic; return flag; case SymbolType.ModEquals: type = OperatorType.ModEquals; category = OperatorCategory.Assignment; return flag; case SymbolType.Dot: type = OperatorType.MemberAccess; category = OperatorCategory.Reference; return flag; case SymbolType.Pointer: type = OperatorType.Pointer; category = OperatorCategory.Reference; return flag; case SymbolType.Colon: type = OperatorType.ConditionalColon; category = OperatorCategory.Conditional; return flag; case SymbolType.QualifiedAlias: type = OperatorType.QualifiedAlias; category = OperatorCategory.Reference; return flag; case SymbolType.QuestionMark: type = OperatorType.ConditionalQuestionMark; category = OperatorCategory.Conditional; return flag; case SymbolType.NullCoalescingSymbol: type = OperatorType.NullCoalescingSymbol; category = OperatorCategory.Logical; return flag; case SymbolType.Tilde: type = OperatorType.BitwiseCompliment; category = OperatorCategory.Unary; return flag; case SymbolType.Lambda: type = OperatorType.Lambda; category = OperatorCategory.Lambda; return flag; } type = OperatorType.AddressOf; category = OperatorCategory.Arithmetic; return false; }
private static OperatorSymbol CreateOperatorToken(Symbol symbol, bool generated) { OperatorType type; OperatorCategory category; if (!GetOperatorType(symbol, out type, out category)) { throw new InvalidOperationException(); } return new OperatorSymbol(symbol.Text, category, type, symbol.Location, generated); }
private Preprocessor GetPreprocessorDirectiveToken(Symbol preprocessorSymbol, bool generated) { int num; string preprocessorDirectiveType = CsParser.GetPreprocessorDirectiveType(preprocessorSymbol, out num); if (preprocessorDirectiveType == null) { throw new SyntaxException(this.document.SourceCode, preprocessorSymbol.LineNumber); } switch (preprocessorDirectiveType) { case "region": { Region region = new Region(preprocessorSymbol.Text, preprocessorSymbol.Location, true, generated); this.symbols.PushRegion(region); return region; } case "endregion": { Region region2 = new Region(preprocessorSymbol.Text, preprocessorSymbol.Location, false, generated); Region region3 = this.symbols.PopRegion(); if (region3 == null) { throw new SyntaxException(this.document.SourceCode, preprocessorSymbol.LineNumber); } region3.Partner = region2; region2.Partner = region3; return region2; } case "if": return this.GetConditionalCompilationDirective(preprocessorSymbol, ConditionalCompilationDirectiveType.If, num, generated); case "elif": return this.GetConditionalCompilationDirective(preprocessorSymbol, ConditionalCompilationDirectiveType.Elif, num, generated); case "else": return this.GetConditionalCompilationDirective(preprocessorSymbol, ConditionalCompilationDirectiveType.Else, num, generated); case "endif": return this.GetConditionalCompilationDirective(preprocessorSymbol, ConditionalCompilationDirectiveType.Endif, num, generated); } return new Preprocessor(preprocessorSymbol.Text, preprocessorSymbol.Location, generated); }
private bool GetOtherElementModifier(string[] allowedModifiers, Dictionary<CsTokenType, CsToken> modifiers, Symbol symbol) { bool flag = true; if (allowedModifiers != null) { for (int i = 0; i < allowedModifiers.Length; i++) { CsTokenType @explicit; CsToken token; if (!string.Equals(symbol.Text, allowedModifiers[i], StringComparison.Ordinal)) { goto Label_014E; } switch (symbol.SymbolType) { case SymbolType.Explicit: @explicit = CsTokenType.Explicit; goto Label_0128; case SymbolType.Extern: @explicit = CsTokenType.Extern; goto Label_0128; case SymbolType.Fixed: @explicit = CsTokenType.Fixed; goto Label_0128; case SymbolType.Implicit: @explicit = CsTokenType.Implicit; goto Label_0128; case SymbolType.New: @explicit = CsTokenType.New; goto Label_0128; case SymbolType.Abstract: @explicit = CsTokenType.Abstract; goto Label_0128; case SymbolType.Const: @explicit = CsTokenType.Const; goto Label_0128; case SymbolType.Override: @explicit = CsTokenType.Override; goto Label_0128; case SymbolType.Readonly: @explicit = CsTokenType.Readonly; goto Label_0128; case SymbolType.Unsafe: @explicit = CsTokenType.Unsafe; goto Label_0128; case SymbolType.Virtual: @explicit = CsTokenType.Virtual; goto Label_0128; case SymbolType.Volatile: @explicit = CsTokenType.Volatile; goto Label_0128; case SymbolType.Other: if (symbol.Text != "partial") { break; } @explicit = CsTokenType.Partial; goto Label_0128; case SymbolType.Static: @explicit = CsTokenType.Static; goto Label_0128; case SymbolType.Sealed: @explicit = CsTokenType.Sealed; goto Label_0128; } throw this.CreateSyntaxException(); Label_0128: token = this.GetToken(@explicit, symbol.SymbolType); modifiers.Add(@explicit, token); this.tokens.Add(token); flag = false; break; Label_014E:; } } return !flag; }
private ConditionalCompilationDirective GetConditionalCompilationDirective(Symbol preprocessorSymbol, ConditionalCompilationDirectiveType type, int startIndex, bool generated) { Expression body = null; if ((type != ConditionalCompilationDirectiveType.Endif) && (startIndex < preprocessorSymbol.Text.Length)) { body = GetConditionalPreprocessorBodyExpression(this.parser, this.document.SourceCode, preprocessorSymbol, startIndex); } return new ConditionalCompilationDirective(preprocessorSymbol.Text, type, body, preprocessorSymbol.Location, generated); }
internal static Expression GetConditionalPreprocessorBodyExpression(CsParser parser, SourceCode sourceCode, Symbol preprocessorSymbol, int startIndex) { string s = preprocessorSymbol.Text.Substring(startIndex, preprocessorSymbol.Text.Length - startIndex).Trim(); if (s.Length > 0) { StringReader code = new StringReader(s); CodeLexer lexer = new CodeLexer(parser, sourceCode, new CodeReader(code)); SymbolManager symbols = new SymbolManager(lexer.GetSymbols(sourceCode, null)); CodeParser parser2 = new CodeParser(parser, symbols); return parser2.GetNextConditionalPreprocessorExpression(sourceCode); } return null; }
private Symbol GetNewLine() { Symbol symbol = null; char character = this.codeReader.Peek(); if (character != char.MinValue) { // Get the character this.codeReader.ReadNext(); // Save the original start and end indexes of the newline character. int startIndex = this.marker.Index; int endIndex = this.marker.Index; // Check if this is an \r\n sequence in which case we need to adjust the end index. if (character == '\r') { character = this.codeReader.Peek(); if (character == '\n') { this.codeReader.ReadNext(); ++this.marker.Index; ++endIndex; } } // Create the code location. CodeLocation location = new CodeLocation( startIndex, endIndex, this.marker.IndexOnLine, this.marker.IndexOnLine + (endIndex - startIndex), this.marker.LineNumber, this.marker.LineNumber); // Create the symbol. symbol = new Symbol("\n", SymbolType.EndOfLine, location); // Update the marker. ++this.marker.Index; ++this.marker.LineNumber; this.marker.IndexOnLine = 0; } return symbol; }
/// <summary> /// Gets the next number. /// </summary> /// <returns>Returns the number.</returns> private Symbol GetNumber() { // The last index of the number. int endIndex = -1; // The first few characters in the number tell us the type of the number. char character = this.codeReader.Peek(); if (character == '-' || character == '+') { // This could be a number starting with a negative or positive sign. // If that's true, the next character must be a digit between 0 and 9. character = this.codeReader.Peek(1); if (character >= '0' && character <= '9') { endIndex = this.GetPositiveNumber(this.marker.Index + 1); } } else { // Get the body of the number. endIndex = this.GetPositiveNumber(this.marker.Index); } // Create the NumberSymbol now. Symbol number = null; // Make sure a number was found. if (endIndex >= this.marker.Index) { // Get the text string for this number. int length = endIndex - this.marker.Index + 1; string numberText = this.codeReader.ReadString(length); Debug.Assert(!string.IsNullOrEmpty(numberText), "The text should not be empty"); // Create the location object. CodeLocation location = new CodeLocation( this.marker.Index, this.marker.Index + length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + length - 1, this.marker.LineNumber, this.marker.LineNumber); number = new Symbol(numberText, SymbolType.Number, location); // Update the marker. this.marker.Index += length; this.marker.IndexOnLine += length; } return number; }
/// <summary> /// Converts a symbol to the given token type. /// </summary> /// <param name="symbol">The symbol to convert.</param> /// <param name="tokenType">The type of the token to retrieve.</param> /// <param name="parentReference">The parent code part.</param> /// <returns>Returns the token.</returns> private CsToken ConvertSymbol(Symbol symbol, CsTokenType tokenType, Reference<ICodePart> parentReference) { Param.AssertNotNull(symbol, "symbol"); Param.Ignore(tokenType); Param.AssertNotNull(parentReference, "parentReference"); // Create the appropriate token based on the type of the symbol. if (symbol.SymbolType == SymbolType.WhiteSpace) { Debug.Assert(tokenType == CsTokenType.WhiteSpace, "The token type is wrong."); return new Whitespace(symbol.Text, symbol.Location, parentReference, this.symbols.Generated); } else if (symbol.SymbolType == SymbolType.Number) { Debug.Assert(tokenType == CsTokenType.Number, "The token type is wrong."); return new Number(symbol.Text, symbol.Location, parentReference, this.symbols.Generated); } else if (symbol.SymbolType == SymbolType.PreprocessorDirective) { Debug.Assert(tokenType == CsTokenType.PreprocessorDirective, "The token type is wrong."); return this.GetPreprocessorDirectiveToken(symbol, parentReference, this.symbols.Generated); } else { // Brackets are created using the GetBracketToken method. Debug.Assert(symbol.SymbolType != SymbolType.OpenParenthesis, "Do not use this method for converting brackets."); Debug.Assert(symbol.SymbolType != SymbolType.CloseParenthesis, "Do not use this method for converting brackets."); Debug.Assert(symbol.SymbolType != SymbolType.OpenSquareBracket, "Do not use this method for converting brackets."); Debug.Assert(symbol.SymbolType != SymbolType.CloseSquareBracket, "Do not use this method for converting brackets."); Debug.Assert(symbol.SymbolType != SymbolType.OpenCurlyBracket, "Do not use this method for converting brackets."); Debug.Assert(symbol.SymbolType != SymbolType.CloseCurlyBracket, "Do not use this method for converting brackets."); Debug.Assert(symbol.SymbolType != SymbolType.Attribute, "Do not use this method for converting attributes."); return new CsToken(symbol.Text, tokenType, CsTokenClass.Token, symbol.Location, parentReference, this.symbols.Generated); } }
/// <summary> /// Gets an unknown symbol type. /// </summary> /// <param name="sourceCode">The source code containing the symbols.</param> /// <returns>Returns the item.</returns> private Symbol GetOtherSymbol(SourceCode sourceCode) { Param.AssertNotNull(sourceCode, "sourceCode"); StringBuilder text = new StringBuilder(); this.ReadToEndOfOtherSymbol(text); if (text.Length == 0) { throw new SyntaxException(sourceCode, this.marker.LineNumber); } string symbolText = text.ToString(); // Get the token location. CodeLocation location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, this.marker.LineNumber); // Create the symbol. Symbol symbol = new Symbol( symbolText, CodeLexer.GetOtherSymbolType(symbolText), location); // Reset the marker index. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; // Return the symbol. return symbol; }
private static bool GetOperatorType(Symbol symbol, out OperatorType type, out OperatorCategory category) { Param.AssertNotNull(symbol, "symbol"); bool isOperator = true; switch (symbol.SymbolType) { case SymbolType.LogicalAnd: type = OperatorType.LogicalAnd; category = OperatorCategory.Logical; break; case SymbolType.LogicalOr: type = OperatorType.LogicalOr; category = OperatorCategory.Logical; break; case SymbolType.LogicalXor: type = OperatorType.LogicalXor; category = OperatorCategory.Logical; break; case SymbolType.ConditionalAnd: type = OperatorType.ConditionalAnd; category = OperatorCategory.Logical; break; case SymbolType.ConditionalOr: type = OperatorType.ConditionalOr; category = OperatorCategory.Logical; break; case SymbolType.NullCoalescingSymbol: type = OperatorType.NullCoalescingSymbol; category = OperatorCategory.Logical; break; case SymbolType.Equals: type = OperatorType.Equals; category = OperatorCategory.Assignment; break; case SymbolType.AndEquals: type = OperatorType.AndEquals; category = OperatorCategory.Assignment; break; case SymbolType.OrEquals: type = OperatorType.OrEquals; category = OperatorCategory.Assignment; break; case SymbolType.PlusEquals: type = OperatorType.PlusEquals; category = OperatorCategory.Assignment; break; case SymbolType.MinusEquals: type = OperatorType.MinusEquals; category = OperatorCategory.Assignment; break; case SymbolType.MultiplicationEquals: type = OperatorType.MultiplicationEquals; category = OperatorCategory.Assignment; break; case SymbolType.DivisionEquals: type = OperatorType.DivisionEquals; category = OperatorCategory.Assignment; break; case SymbolType.ModEquals: type = OperatorType.ModEquals; category = OperatorCategory.Assignment; break; case SymbolType.XorEquals: type = OperatorType.XorEquals; category = OperatorCategory.Assignment; break; case SymbolType.LeftShiftEquals: type = OperatorType.LeftShiftEquals; category = OperatorCategory.Assignment; break; case SymbolType.RightShiftEquals: type = OperatorType.RightShiftEquals; category = OperatorCategory.Assignment; break; case SymbolType.ConditionalEquals: type = OperatorType.ConditionalEquals; category = OperatorCategory.Relational; break; case SymbolType.NotEquals: type = OperatorType.NotEquals; category = OperatorCategory.Relational; break; case SymbolType.LessThan: type = OperatorType.LessThan; category = OperatorCategory.Relational; break; case SymbolType.GreaterThan: type = OperatorType.GreaterThan; category = OperatorCategory.Relational; break; case SymbolType.LessThanOrEquals: type = OperatorType.LessThanOrEquals; category = OperatorCategory.Relational; break; case SymbolType.GreaterThanOrEquals: type = OperatorType.GreaterThanOrEquals; category = OperatorCategory.Relational; break; case SymbolType.Plus: type = OperatorType.Plus; category = OperatorCategory.Arithmetic; break; case SymbolType.Minus: type = OperatorType.Minus; category = OperatorCategory.Arithmetic; break; case SymbolType.Multiplication: type = OperatorType.Multiplication; category = OperatorCategory.Arithmetic; break; case SymbolType.Division: type = OperatorType.Division; category = OperatorCategory.Arithmetic; break; case SymbolType.Mod: type = OperatorType.Mod; category = OperatorCategory.Arithmetic; break; case SymbolType.LeftShift: type = OperatorType.LeftShift; category = OperatorCategory.Shift; break; case SymbolType.RightShift: type = OperatorType.RightShift; category = OperatorCategory.Shift; break; case SymbolType.Increment: type = OperatorType.Increment; category = OperatorCategory.IncrementDecrement; break; case SymbolType.Decrement: type = OperatorType.Decrement; category = OperatorCategory.IncrementDecrement; break; case SymbolType.QuestionMark: type = OperatorType.ConditionalQuestionMark; category = OperatorCategory.Conditional; break; case SymbolType.Colon: type = OperatorType.ConditionalColon; category = OperatorCategory.Conditional; break; case SymbolType.Pointer: type = OperatorType.Pointer; category = OperatorCategory.Reference; break; case SymbolType.Dot: type = OperatorType.MemberAccess; category = OperatorCategory.Reference; break; case SymbolType.QualifiedAlias: type = OperatorType.QualifiedAlias; category = OperatorCategory.Reference; break; case SymbolType.Not: type = OperatorType.Not; category = OperatorCategory.Unary; break; case SymbolType.Tilde: type = OperatorType.BitwiseCompliment; category = OperatorCategory.Unary; break; case SymbolType.Lambda: type = OperatorType.Lambda; category = OperatorCategory.Lambda; break; default: // Assign random values. type = OperatorType.AddressOf; category = OperatorCategory.Arithmetic; // Signal that the symbol is not an operator. isOperator = false; break; } return isOperator; }
/// <summary> /// Gets the next string from the code. /// </summary> /// <returns>Returns the string.</returns> private Symbol GetString() { StringBuilder text = new StringBuilder(); // Read the opening quote character and add it to the string. char quoteType = this.codeReader.ReadNext(); Debug.Assert(quoteType == '\'' || quoteType == '\"', "Expected a quote character"); text.Append(quoteType); bool slash = false; // Read through to the end of the string. while (true) { char character = this.codeReader.Peek(); if (character == char.MinValue || (character == quoteType && !slash)) { // This is the end of the string. Add the character and quit. text.Append(character); this.codeReader.ReadNext(); break; } if (character == '\\') { slash = !slash; } else { slash = false; if (character == '\r' || character == '\n') { // We've hit the end of the line. Just exit. break; } } text.Append(character); // Advance past this character. this.codeReader.ReadNext(); } // Create the code location. CodeLocation location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, this.marker.LineNumber); // Create the symbol. Symbol symbol = new Symbol(text.ToString(), SymbolType.String, location); // Update the marker. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; // Return the symbol. return symbol; }
private bool GetOtherElementModifier( Reference<ICodePart> elementReference, string[] allowedModifiers, Dictionary<CsTokenType, CsToken> modifiers, Symbol symbol) { Param.AssertNotNull(elementReference, "elementReference"); Param.Ignore(allowedModifiers); Param.AssertNotNull(modifiers, "modifiers"); Param.AssertNotNull(symbol, "symbol"); bool stop = true; // If the modifier is one of the allowed modifiers, store it. Otherwise, we are done. if (allowedModifiers != null) { for (int i = 0; i < allowedModifiers.Length; ++i) { if (string.Equals(symbol.Text, allowedModifiers[i], StringComparison.Ordinal)) { CsTokenType modifierType; switch (symbol.SymbolType) { case SymbolType.Abstract: modifierType = CsTokenType.Abstract; break; case SymbolType.Const: modifierType = CsTokenType.Const; break; case SymbolType.Explicit: modifierType = CsTokenType.Explicit; break; case SymbolType.Extern: modifierType = CsTokenType.Extern; break; case SymbolType.Implicit: modifierType = CsTokenType.Implicit; break; case SymbolType.New: modifierType = CsTokenType.New; break; case SymbolType.Override: modifierType = CsTokenType.Override; break; case SymbolType.Readonly: modifierType = CsTokenType.Readonly; break; case SymbolType.Sealed: modifierType = CsTokenType.Sealed; break; case SymbolType.Static: modifierType = CsTokenType.Static; break; case SymbolType.Unsafe: modifierType = CsTokenType.Unsafe; break; case SymbolType.Virtual: modifierType = CsTokenType.Virtual; break; case SymbolType.Volatile: modifierType = CsTokenType.Volatile; break; case SymbolType.Fixed: modifierType = CsTokenType.Fixed; break; case SymbolType.Other: if (symbol.Text != "partial") { goto default; } modifierType = CsTokenType.Partial; break; default: throw this.CreateSyntaxException(); } CsToken modifier = this.GetToken(modifierType, symbol.SymbolType, elementReference); modifiers.Add(modifierType, modifier); this.tokens.Add(modifier); stop = false; break; } } } return !stop; }
/// <summary> /// Gets the next whitespace stream. /// </summary> /// <returns>Returns the whitespace.</returns> private Symbol GetWhitespace() { StringBuilder text = new StringBuilder(); // Get all of the characters in the whitespace. while (true) { char character = this.codeReader.Peek(); if (character == char.MinValue || (character != ' ' && character != '\t')) { break; } text.Append(character); // Advance past this character. this.codeReader.ReadNext(); } // Create the whitespace location object. CodeLocation location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, this.marker.LineNumber); // Create the whitespace object. Symbol whitespace = new Symbol(text.ToString(), SymbolType.WhiteSpace, location); // Update the marker. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; // Return the whitespace object. return whitespace; }
/// <summary> /// Extracts an if, endif, or else directive. /// </summary> /// <param name="sourceCode">The source code being parsed.</param> /// <param name="preprocessorSymbol">The preprocessor symbol being parsed.</param> /// <param name="configuration">The current code configuration.</param> /// <param name="startIndex">The start index of the item within the symbols.</param> /// <param name="type">The type of the preprocessor symbol.</param> /// <param name="skip">Returns a value indicating whether the item should be skipped.</param> /// <returns>Returns a value indicating whether to ignore the item.</returns> private bool GetIfElsePreprocessorDirectives( SourceCode sourceCode, Symbol preprocessorSymbol, Configuration configuration, int startIndex, string type, out bool skip) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.AssertNotNull(configuration, "configuration"); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); Param.AssertValidString(type, "type"); bool ignore = false; skip = false; if (type == "if") { // Add this directive to the stack and indicate that it has not been entered. this.conditionalDirectives.Push(false); // Extract the body of the directive. Expression body = CodeParser.GetConditionalPreprocessorBodyExpression( this.parser, sourceCode, preprocessorSymbol, startIndex); if (body == null) { throw new SyntaxException(sourceCode, preprocessorSymbol.LineNumber); } // Determine whether the code under this directive needs to be skipped because it is out of scope. skip = !this.EvaluateConditionalDirectiveExpression(sourceCode, body, configuration); } else if (type == "elif") { if (this.conditionalDirectives.Count == 0) { throw new SyntaxException(sourceCode, preprocessorSymbol.LineNumber); } bool entered = this.conditionalDirectives.Peek(); if (entered) { skip = true; } else { // Extract the body of the directive. Expression body = CodeParser.GetConditionalPreprocessorBodyExpression( this.parser, sourceCode, preprocessorSymbol, startIndex); if (body != null) { // Determine whether the code under this directive needs to be skipped because it is out of scope. skip = !this.EvaluateConditionalDirectiveExpression(sourceCode, body, configuration); } } } else if (type == "else") { if (this.conditionalDirectives.Count == 0) { throw new SyntaxException(sourceCode, preprocessorSymbol.LineNumber); } bool entered = this.conditionalDirectives.Peek(); if (entered) { skip = true; } } else { // This is not a conditional preprocessor directive. ignore = true; } return ignore; }
/// <summary> /// Checks the given preprocessor symbol to determine whether it is a conditional preprocessor directive. /// If so, determines whether we should skip past code which is out of scope. /// </summary> /// <param name="sourceCode">The source code file containing this directive.</param> /// <param name="preprocessorSymbol">The symbol to check.</param> /// <param name="configuration">The active configuration.</param> private void CheckForConditionalCompilationDirective( SourceCode sourceCode, Symbol preprocessorSymbol, Configuration configuration) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.Ignore(configuration); // Get the type of this preprocessor directive. int bodyIndex; string type = CsParser.GetPreprocessorDirectiveType(preprocessorSymbol, out bodyIndex); if (type == "define") { this.GetDefinePreprocessorDirective(sourceCode, preprocessorSymbol, bodyIndex); } else if (type == "undef") { this.GetUndefinePreprocessorDirective(sourceCode, preprocessorSymbol, bodyIndex); } else if (type == "endif") { // Pop this conditional directive off of the stack. if (this.conditionalDirectives.Count == 0) { throw new SyntaxException(sourceCode, preprocessorSymbol.LineNumber); } this.conditionalDirectives.Pop(); } else { // Extract an if, endif, or else directive. bool skip; if (!this.GetIfElsePreprocessorDirectives( sourceCode, preprocessorSymbol, configuration, bodyIndex, type, out skip)) { // Check whether the code needs to be skipped. if (skip) { // We will skip all code between this conditional preprocessor symbol and the next one. int subConditionalPreprocessorCount = 0; while (true) { // Get the next symbol. Symbol symbol = this.GetSymbol(sourceCode, configuration, false); if (symbol == null) { throw new SyntaxException(sourceCode, preprocessorSymbol.LineNumber); } // Check whether this is another preprocessor. if (symbol.SymbolType == SymbolType.PreprocessorDirective) { // Check to see if this is a conditional preprocessor symbol, which indicates that we have // reached the end of out-of-scope code. type = CsParser.GetPreprocessorDirectiveType(symbol, out bodyIndex); if (type == "if") { ++subConditionalPreprocessorCount; } else if (subConditionalPreprocessorCount > 0 && type == "endif") { --subConditionalPreprocessorCount; } else if (subConditionalPreprocessorCount == 0 && (type == "elif" || type == "else" || type == "endif")) { // Reset the markers to the start of this preprocessor symbol. this.marker.Index = symbol.Location.StartPoint.Index; this.marker.IndexOnLine = symbol.Location.StartPoint.IndexOnLine; this.marker.LineNumber = symbol.Location.StartPoint.LineNumber; // Break from this loop. break; } } } } else { // Indicate that this conditional directive has been entered. if (this.conditionalDirectives.Count == 0) { throw new SyntaxException(sourceCode, preprocessorSymbol.LineNumber); } this.conditionalDirectives.Pop(); this.conditionalDirectives.Push(true); } } } }
/// <summary> /// Gets the next literal keyword token from the code. /// </summary> /// <param name="text">The text buffer to add the string text to.</param> /// <returns>Returns the literal keyword token.</returns> private Symbol GetLiteralKeyword(StringBuilder text) { Param.AssertNotNull(text, "text"); Debug.Assert(text.Length > 0 && text[0] == '@', "Expected an @ character"); // Advance to the end of the token. this.ReadToEndOfOtherSymbol(text); if (text.Length == 1) { // Nothing was read. throw new SyntaxException(this.source, this.marker.LineNumber); } // Get the token location. CodeLocation location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, this.marker.LineNumber); // Create the symbol. Symbol symbol = new Symbol(text.ToString(), SymbolType.Other, location); // Reset the marker index. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; // Return the symbol. return symbol; }
/// <summary> /// Gets and converts preprocessor directive. /// </summary> /// <param name="preprocessorSymbol">The preprocessor symbol.</param> /// <param name="parent">The parent code part.</param> /// <param name="generated">Indicates whether the preprocessor directive lies within a block of generated code.</param> /// <returns>Returns the preprocessor directive.</returns> private Preprocessor GetPreprocessorDirectiveToken(Symbol preprocessorSymbol, Reference<ICodePart> parent, bool generated) { Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.AssertNotNull(parent, "parent"); Param.Ignore(generated); Debug.Assert(preprocessorSymbol != null && preprocessorSymbol.SymbolType == SymbolType.PreprocessorDirective, "Expected a preprocessor directive"); // Get the type of the preprocessor directive. int bodyIndex; string type = CsParser.GetPreprocessorDirectiveType(preprocessorSymbol, out bodyIndex); if (type == null) { throw new SyntaxException(this.document.SourceCode, preprocessorSymbol.LineNumber); } // Create the correct preprocessor object type. Preprocessor preprocessor = null; if (type == "region") { Region region = new Region(preprocessorSymbol.Text, preprocessorSymbol.Location, parent, true, generated); this.symbols.PushRegion(region); preprocessor = region; } else if (type == "endregion") { Region endregion = new Region(preprocessorSymbol.Text, preprocessorSymbol.Location, parent, false, generated); Region startregion = this.symbols.PopRegion(); if (startregion == null) { throw new SyntaxException(this.document.SourceCode, preprocessorSymbol.LineNumber); } startregion.Partner = endregion; endregion.Partner = startregion; preprocessor = endregion; } else if (type == "if") { preprocessor = this.GetConditionalCompilationDirective( preprocessorSymbol, ConditionalCompilationDirectiveType.If, bodyIndex, parent, generated); } else if (type == "elif") { preprocessor = this.GetConditionalCompilationDirective( preprocessorSymbol, ConditionalCompilationDirectiveType.Elif, bodyIndex, parent, generated); } else if (type == "else") { preprocessor = this.GetConditionalCompilationDirective( preprocessorSymbol, ConditionalCompilationDirectiveType.Else, bodyIndex, parent, generated); } else if (type == "endif") { preprocessor = this.GetConditionalCompilationDirective( preprocessorSymbol, ConditionalCompilationDirectiveType.Endif, bodyIndex, parent, generated); } else { preprocessor = new Preprocessor(preprocessorSymbol.Text, preprocessorSymbol.Location, parent, generated); } return preprocessor; }
/// <summary> /// Gets the next literal string from the code. /// </summary> /// <param name="text">The text buffer to add the string text to.</param> /// <returns>Returns the literal string.</returns> private Symbol GetLiteralString(StringBuilder text) { Param.AssertNotNull(text, "text"); Debug.Assert(text.Length == 1 && text[0] == '@', "Expected an @ symbol"); // Initialize the location of the start of the string. int startIndex = this.marker.Index; int endIndex = this.marker.Index; int startIndexOnLine = this.marker.IndexOnLine; int endIndexOnLine = this.marker.IndexOnLine; int lineNumber = this.marker.LineNumber; int endLineNumber = this.marker.LineNumber; // Get the opening string character to determine what type of string this is. char stringType = this.codeReader.Peek(); Debug.Assert(stringType == '\'' || stringType == '\"', "Expected a quote character"); // Add the opening quote character and move past it. text.Append(stringType); this.codeReader.ReadNext(); // Advance the end indexes past the literal character and the open quote character. endIndex += 2; endIndexOnLine += 2; while (true) { char character = this.codeReader.Peek(); if (character == char.MinValue) { // No more characters in the buffer. break; } else if (character == stringType) { // Read the character and add it to the text buffer. this.codeReader.ReadNext(); text.Append(character); ++endIndex; ++endIndexOnLine; // If the next character is also the same string type, then this is internal to the string. character = this.codeReader.Peek(); if (character == stringType) { // Also move past this character and add it. this.codeReader.ReadNext(); text.Append(character); ++endIndex; ++endIndexOnLine; continue; } else { // This is the end of the string. We're done now. break; } } else if (character == '\r' || character == '\n') { if (stringType == '\'') { // This is a syntax error in the code as single-quoted literal strings // cannot allowed to span across multiple lines, although double-quoted // strings can. throw new SyntaxException(this.source, this.marker.LineNumber); } else if (character == '\n') { ++endLineNumber; endIndexOnLine = -1; } else if (character == '\r') { // Just move past this character without adding it. this.codeReader.ReadNext(); continue; } } this.codeReader.ReadNext(); text.Append(character); ++endIndex; ++endIndexOnLine; } // Make sure the end index is correct now. if (text.Length <= 2 || text[text.Length - 1] != stringType) { throw new SyntaxException(this.source, this.marker.LineNumber); } // Create the location object. CodeLocation location = new CodeLocation( startIndex, endIndex, startIndexOnLine, endIndexOnLine, lineNumber, endLineNumber); // Create the symbol. Symbol token = new Symbol(text.ToString(), SymbolType.String, location); // Update the marker. this.marker.Index = endIndex + 1; this.marker.IndexOnLine = endIndexOnLine + 1; this.marker.LineNumber = endLineNumber; // Return the token. return token; }
internal static string GetPreprocessorDirectiveType(Symbol preprocessor, out int bodyIndex) { bodyIndex = -1; int startIndex = -1; int num2 = -1; for (int i = 1; i < preprocessor.Text.Length; i++) { if (char.IsLetter(preprocessor.Text[i])) { startIndex = i; break; } } if (startIndex == -1) { return null; } num2 = startIndex; while (num2 < preprocessor.Text.Length) { if (!char.IsLetter(preprocessor.Text[num2])) { break; } num2++; } num2--; if (num2 < startIndex) { return null; } bodyIndex = num2 + 1; return preprocessor.Text.Substring(startIndex, (num2 - startIndex) + 1); }
/// <summary> /// Gets the next multi-line comment. /// </summary> /// <param name="text">The buffer to add the text to.</param> /// <returns>Returns the comment.</returns> private Symbol GetMultiLineComment(StringBuilder text) { Param.AssertNotNull(text, "text"); // Initialize the location of the start of the comment. Add one to the end indexes since we know the // comment starts with /*, which is two characters long. int startIndex = this.marker.Index; int endIndex = this.marker.Index + 1; int startIndexOnLine = this.marker.IndexOnLine; int endIndexOnLine = this.marker.IndexOnLine + 1; int lineNumber = this.marker.LineNumber; int endLineNumber = this.marker.LineNumber; // Initialize loop trackers. bool asterisk = false; bool first = false; // Find the end of the comment. while (true) { char character = this.codeReader.Peek(); if (character == char.MinValue) { break; } // Add the character and move the index past it. text.Append(this.codeReader.ReadNext()); if (asterisk && character == '/') { // This is the end of the comment. break; } else { if (character == '*') { if (first) { // Mark the asterisk. asterisk = true; } else { first = true; } } else { // This is not an asterisk. asterisk = false; // Check for newlines. if (character == '\n') { ++endLineNumber; endIndexOnLine = -1; } else if (character == '\r') { // Peek at the next character and check the type. character = this.codeReader.Peek(); if (character != '\n') { ++endLineNumber; endIndexOnLine = -1; } } } } ++endIndex; ++endIndexOnLine; } // Create the location object. CodeLocation location = new CodeLocation( startIndex, endIndex, startIndexOnLine, endIndexOnLine, lineNumber, endLineNumber); // Create the symbol object. Symbol symbol = new Symbol(text.ToString(), SymbolType.MultiLineComment, location); // Update the marker. this.marker.Index = endIndex + 1; this.marker.IndexOnLine = endIndexOnLine + 1; this.marker.LineNumber = endLineNumber; // Return the symbol. return symbol; }