} // AddString // If the current position of the TextReaderBuffer matches any // of our registered strings, then set length to the length of the // longest such string, set info to the value supplied in AddString, // and return true. Otherwise leave length and info undefined, and // return false. public bool Match(TextReaderBuffer reader, out int length, out int info) { // We don't really need to assign length and info here, but we do so // so that the compiler won't complain on any of the "return false" // paths. length = 0; info = 0; char[] buffer; int bufStart; int bufLen = reader.GetBuffer(maxLen, out buffer, out bufStart); if (bufLen <= 0) { return(false); } // NOTE (snewman 7/12/01): this is currently implemented as a // simple linear search over all registered strings, after // discriminating by the initial character. Many more efficient // algorithms are possible, such as binary search or tries. Doesn't // seem worthwhile. int initialChar = buffer[bufStart]; bufStart++; bufLen--; if (initialChar >= strings.Length) { return(false); } for (StringEntry candidate = strings[initialChar]; candidate != null; candidate = candidate.next) { if (bufLen >= candidate.headlessString.Length && MatchChars(buffer, bufStart, candidate.headlessString)) { if (!candidate.isIdentifier || bufLen == candidate.headlessString.Length || !CharUtils.IsIdentifierChar(buffer[bufStart + candidate.headlessString.Length])) { length = candidate.headlessString.Length + 1; info = candidate.info; return(true); } } } return(false); } // Match
} // ParseStringLiteral // Advance the stream past a comment beginning at the current stream // location. private void SkipComment(SrcLoc loc) { // HACK SN 7/13/01: rewrite this to support comments longer // than maxTokenLen. // Get a buffer from which we can parse the comment. char[] charBuf; int startPos; int bufLen = buffer.GetBuffer(maxTokenLen, out charBuf, out startPos); int tokenLen = 2; if (charBuf[startPos + 1] == '/') { // C++ style comment; search for end of line while (tokenLen < bufLen && !CharUtils.IsEOLChar(charBuf[startPos + tokenLen])) { tokenLen++; } } else { // C style comment; search for "*/" // NOTE: we might extend this to warn for nested comments. while (tokenLen < bufLen - 1 && (charBuf[startPos + tokenLen] != '*' || charBuf[startPos + tokenLen + 1] != '/')) { tokenLen++; } if (tokenLen >= bufLen - 1) { loc.len = tokenLen; throw new ParseError("unterminated /* comment", loc); } // Include the trailing "*/" in tokenLen. tokenLen += 2; } buffer.Skip(tokenLen); } // SkipComment
} // SkipComment // Advance the stream past a block of whitespace beginning at the // current stream location. // // NOTE: the current implementation of this method will only skip // up to one buffer's worth of whitespace. This simplifies the // implementation, and is OK because we'll just skip any remaining // whitespace in the next go-around of the tokenizer loop. private void SkipWhitespace() { // Get a buffer from which we can search for whitespace. char[] charBuf; int startPos; int bufLen = buffer.GetBuffer(maxTokenLen, out charBuf, out startPos); int tokenLen = 1; while (tokenLen < bufLen && CharUtils.IsWhitespaceChar(charBuf[startPos + tokenLen])) { tokenLen++; } buffer.Skip(tokenLen); } // SkipWhitespace
} // ParseIdentifier // Parse a numeric literal beginning at the current stream location. private Token ParseNumber(SrcLoc loc) { // Get a buffer from which we can parse the number. char[] charBuf; int startPos; int bufLen = buffer.GetBuffer(maxTokenLen, out charBuf, out startPos); if (bufLen > maxTokenLen) { bufLen = maxTokenLen; } // Find the end of the number. We match for the following // components: // // integer part (1 or more digits) // optional fractional part ('.' plus one or more digits) // optional exponent ('E' or 'e', optional '+' or '-', and 1-3 digits) // // HACK SN 7/14/01: for now, we aren't enforcing that the fractional // part must have at least one digit, or that the exponent must have // at least 1 and no more than 3 digits. Review the ECMAScript spec for // the correct rules. Also, should we allow numbers that begin with a '.' // (no integer part)? int tokenLen = 0; while (tokenLen < bufLen && CharUtils.IsDigitChar(charBuf[startPos + tokenLen])) { tokenLen++; } if (tokenLen < bufLen && charBuf[startPos + tokenLen] == '.') { tokenLen++; while (tokenLen < bufLen && CharUtils.IsDigitChar(charBuf[startPos + tokenLen])) { tokenLen++; } } if (tokenLen < bufLen && (charBuf[startPos + tokenLen] == 'E' || charBuf[startPos + tokenLen] == 'e')) { tokenLen++; if (tokenLen < bufLen && (charBuf[startPos + tokenLen] == '+' || charBuf[startPos + tokenLen] == '-')) { tokenLen++; } while (tokenLen < bufLen && CharUtils.IsDigitChar(charBuf[startPos + tokenLen])) { tokenLen++; } } NumLit token = new NumLit(); token.rawText = buffer.ConsumeString(tokenLen); loc.len = tokenLen; token.loc = loc; try { token.value = Double.Parse(token.rawText); } catch (FormatException e) { throw new ParseError("FormatException parsing numeric literal \"" + token.rawText + "\": " + e.ToString(), loc); } catch (OverflowException e) { throw new ParseError("OverflowException parsing numeric literal \"" + token.rawText + "\": " + e.ToString(), loc); } return(token); } // ParseNumber