/// <summary> /// /// </summary> /// <param name="stream"></param> /// <returns></returns> /// <remarks> /// /// See https://www.dmtf.org/sites/default/files/standards/documents/DSP0221_3.0.1.pdf /// /// 5.4 Comments /// /// Comments in a MOF file do not create, modify, or annotate language elements. They shall be treated as if /// they were whitespace. /// /// Comments may appear anywhere in MOF syntax where whitespace is allowed and are indicated by either /// a leading double slash (//) or a pair of matching /* and */ character sequences. Occurrences of these /// character sequences in string literals shall not be treated as comments. /// /// A // comment is terminated by the end of line (see 5.3), as shown in the example below. /// /// Integer MyProperty; // This is an example of a single-line comment /// /// A comment that begins with /* is terminated by the next */ sequence, or by the end of the MOF file, /// whichever comes first. /// /// /* example of a comment between property definition tokens and a multi-line comment */ /// Integer /* 16-bit integer property */ MyProperty; /* and a multi-line /// comment */ /// /// </remarks> public static (CommentToken, Lexer) ReadCommentToken(SourceReader reader) { var thisReader = reader; var sourceChar = default(SourceChar); var sourceChars = new List <SourceChar>(); // read the starting '/' (sourceChar, thisReader) = thisReader.Read('/'); sourceChars.Add(sourceChar); switch (thisReader.Peek().Value) { case '/': // single-line (sourceChar, thisReader) = thisReader.Read('/'); sourceChars.Add(sourceChar); // read the comment text while (!thisReader.Eof() && !thisReader.Peek(StringValidator.IsLineTerminator)) { (sourceChar, thisReader) = thisReader.Read(); sourceChars.Add(sourceChar); } ; break; case '*': // multi-line (sourceChar, thisReader) = thisReader.Read('*'); sourceChars.Add(sourceChar); // read the comment text while (!thisReader.Eof()) { (sourceChar, thisReader) = thisReader.Read(); sourceChars.Add(sourceChar); if ((sourceChar.Value == '*') && thisReader.Peek('/')) { // read the closing sequence (sourceChar, thisReader) = thisReader.Read('/'); sourceChars.Add(sourceChar); break; } } break; default: throw new UnexpectedCharacterException(reader.Peek()); } // return the result var extent = SourceExtent.From(sourceChars); return(new CommentToken(extent), new Lexer(thisReader)); }
public ScannerResult ReadToken(SourceReader reader) { var peek = reader.Peek(); // make sure the rule for the next character is in the rule cache if (!this.ScannerCache.ContainsKey(peek.Value)) { this.ScannerCache.Add( peek.Value, this.Scanners.FirstOrDefault(r => r.Match.Matches(peek.Value)) ?? throw new UnexpectedCharacterException(peek) ); } // apply the scanner for the next character return(this.ScannerCache[peek.Value].Action.Invoke(reader)); }
public IEnumerable <Token> Scan() { while (!reader.EndOfStream) { reader.ReadWhile(Char.IsWhiteSpace); var startLocation = reader.Location; var lexeme = String.Empty; var tokenKind = TokenKind.Unknown; var c = (char)reader.Peek(); switch (c) { case '+': reader.Read(); tokenKind = TokenKind.Plus; lexeme = "+"; break; case '-': reader.Read(); tokenKind = TokenKind.Minus; lexeme = "-"; break; case '*': reader.Read(); tokenKind = TokenKind.Mul; lexeme = "*"; break; case '/': reader.Read(); tokenKind = TokenKind.Div; lexeme = "/"; break; case '(': reader.Read(); tokenKind = TokenKind.LParen; lexeme = "("; break; case ')': reader.Read(); tokenKind = TokenKind.RParen; lexeme = ")"; break; case '[': reader.Read(); tokenKind = TokenKind.LBracket; lexeme = "["; break; case ']': reader.Read(); tokenKind = TokenKind.RBracket; lexeme = "]"; break; case '{': reader.Read(); tokenKind = TokenKind.LCurly; lexeme = "{"; break; case '}': reader.Read(); tokenKind = TokenKind.RCurly; lexeme = "}"; break; case ',': reader.Read(); tokenKind = TokenKind.Comma; lexeme = ","; break; case '.': reader.Read(); tokenKind = TokenKind.Period; lexeme = "."; break; case ';': reader.Read(); tokenKind = TokenKind.Semicolon; lexeme = ";"; break; case ':': reader.Read(); tokenKind = TokenKind.Colon; lexeme = ":"; break; case '?': reader.Read(); if (reader.Peek() == '?') { reader.Read(); tokenKind = TokenKind.QMark2; lexeme = "??"; } else { tokenKind = TokenKind.QMark; lexeme = "?"; } break; case '!': reader.Read(); tokenKind = TokenKind.EMark; lexeme = "!"; break; default: if (Char.IsDigit(c)) { lexeme = reader.ReadWhile(Char.IsDigit); tokenKind = TokenKind.Number; } else if (Char.IsLetterOrDigit(c)) { lexeme = reader.ReadWhile(Char.IsLetterOrDigit); if (!keywords.TryGetValue(lexeme, out tokenKind)) { tokenKind = TokenKind.Ident; } } else { lexeme = reader.ReadWhile(x => !Char.IsWhiteSpace(x)); } break; } yield return(new Token(tokenKind, lexeme, new TextSpan(startLocation, reader.Location))); } yield return(new Token(TokenKind.Eof, "end of file", new TextSpan(reader.Location, reader.Location))); }