tokenizer.h
Go to the documentation of this file.
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 // Author: kenton@google.com (Kenton Varda)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
34 //
35 // Class for parsing tokenized text from a ZeroCopyInputStream.
36 
37 #ifndef GOOGLE_PROTOBUF_IO_TOKENIZER_H__
38 #define GOOGLE_PROTOBUF_IO_TOKENIZER_H__
39 
40 #include <string>
41 #include <vector>
44 
45 #include <google/protobuf/port_def.inc>
46 
47 namespace google {
48 namespace protobuf {
49 namespace io {
50 
51 class ZeroCopyInputStream; // zero_copy_stream.h
52 
53 // Defined in this file.
54 class ErrorCollector;
55 class Tokenizer;
56 
57 // By "column number", the proto compiler refers to a count of the number
58 // of bytes before a given byte, except that a tab character advances to
59 // the next multiple of 8 bytes. Note in particular that column numbers
60 // are zero-based, while many user interfaces use one-based column numbers.
61 typedef int ColumnNumber;
62 
63 // Abstract interface for an object which collects the errors that occur
64 // during parsing. A typical implementation might simply print the errors
65 // to stdout.
66 class PROTOBUF_EXPORT ErrorCollector {
67  public:
68  inline ErrorCollector() {}
69  virtual ~ErrorCollector();
70 
71  // Indicates that there was an error in the input at the given line and
72  // column numbers. The numbers are zero-based, so you may want to add
73  // 1 to each before printing them.
74  virtual void AddError(int line, ColumnNumber column,
75  const std::string& message) = 0;
76 
77  // Indicates that there was a warning in the input at the given line and
78  // column numbers. The numbers are zero-based, so you may want to add
79  // 1 to each before printing them.
80  virtual void AddWarning(int line, ColumnNumber column,
81  const std::string& message) {}
82 
83  private:
85 };
86 
87 // This class converts a stream of raw text into a stream of tokens for
88 // the protocol definition parser to parse. The tokens recognized are
89 // similar to those that make up the C language; see the TokenType enum for
90 // precise descriptions. Whitespace and comments are skipped. By default,
91 // C- and C++-style comments are recognized, but other styles can be used by
92 // calling set_comment_style().
93 class PROTOBUF_EXPORT Tokenizer {
94  public:
95  // Construct a Tokenizer that reads and tokenizes text from the given
96  // input stream and writes errors to the given error_collector.
97  // The caller keeps ownership of input and error_collector.
99  ~Tokenizer();
100 
101  enum TokenType {
102  TYPE_START, // Next() has not yet been called.
103  TYPE_END, // End of input reached. "text" is empty.
104 
105  TYPE_IDENTIFIER, // A sequence of letters, digits, and underscores, not
106  // starting with a digit. It is an error for a number
107  // to be followed by an identifier with no space in
108  // between.
109  TYPE_INTEGER, // A sequence of digits representing an integer. Normally
110  // the digits are decimal, but a prefix of "0x" indicates
111  // a hex number and a leading zero indicates octal, just
112  // like with C numeric literals. A leading negative sign
113  // is NOT included in the token; it's up to the parser to
114  // interpret the unary minus operator on its own.
115  TYPE_FLOAT, // A floating point literal, with a fractional part and/or
116  // an exponent. Always in decimal. Again, never
117  // negative.
118  TYPE_STRING, // A quoted sequence of escaped characters. Either single
119  // or double quotes can be used, but they must match.
120  // A string literal cannot cross a line break.
121  TYPE_SYMBOL, // Any other printable character, like '!' or '+'.
122  // Symbols are always a single character, so "!+$%" is
123  // four tokens.
124  };
125 
126  // Structure representing a token read from the token stream.
127  struct Token {
129  std::string text; // The exact text of the token as it appeared in
130  // the input. e.g. tokens of TYPE_STRING will still
131  // be escaped and in quotes.
132 
133  // "line" and "column" specify the position of the first character of
134  // the token within the input stream. They are zero-based.
135  int line;
138  };
139 
140  // Get the current token. This is updated when Next() is called. Before
141  // the first call to Next(), current() has type TYPE_START and no contents.
142  const Token& current();
143 
144  // Return the previous token -- i.e. what current() returned before the
145  // previous call to Next().
146  const Token& previous();
147 
148  // Advance to the next token. Returns false if the end of the input is
149  // reached.
150  bool Next();
151 
152  // Like Next(), but also collects comments which appear between the previous
153  // and next tokens.
154  //
155  // Comments which appear to be attached to the previous token are stored
156  // in *prev_tailing_comments. Comments which appear to be attached to the
157  // next token are stored in *next_leading_comments. Comments appearing in
158  // between which do not appear to be attached to either will be added to
159  // detached_comments. Any of these parameters can be NULL to simply discard
160  // the comments.
161  //
162  // A series of line comments appearing on consecutive lines, with no other
163  // tokens appearing on those lines, will be treated as a single comment.
164  //
165  // Only the comment content is returned; comment markers (e.g. //) are
166  // stripped out. For block comments, leading whitespace and an asterisk will
167  // be stripped from the beginning of each line other than the first. Newlines
168  // are included in the output.
169  //
170  // Examples:
171  //
172  // optional int32 foo = 1; // Comment attached to foo.
173  // // Comment attached to bar.
174  // optional int32 bar = 2;
175  //
176  // optional string baz = 3;
177  // // Comment attached to baz.
178  // // Another line attached to baz.
179  //
180  // // Comment attached to qux.
181  // //
182  // // Another line attached to qux.
183  // optional double qux = 4;
184  //
185  // // Detached comment. This is not attached to qux or corge
186  // // because there are blank lines separating it from both.
187  //
188  // optional string corge = 5;
189  // /* Block comment attached
190  // * to corge. Leading asterisks
191  // * will be removed. */
192  // /* Block comment attached to
193  // * grault. */
194  // optional int32 grault = 6;
195  bool NextWithComments(std::string* prev_trailing_comments,
196  std::vector<std::string>* detached_comments,
198 
199  // Parse helpers ---------------------------------------------------
200 
201  // Parses a TYPE_FLOAT token. This never fails, so long as the text actually
202  // comes from a TYPE_FLOAT token parsed by Tokenizer. If it doesn't, the
203  // result is undefined (possibly an assert failure).
204  static double ParseFloat(const std::string& text);
205 
206  // Parses a TYPE_STRING token. This never fails, so long as the text actually
207  // comes from a TYPE_STRING token parsed by Tokenizer. If it doesn't, the
208  // result is undefined (possibly an assert failure).
209  static void ParseString(const std::string& text, std::string* output);
210 
211  // Identical to ParseString, but appends to output.
212  static void ParseStringAppend(const std::string& text, std::string* output);
213 
214  // Parses a TYPE_INTEGER token. Returns false if the result would be
215  // greater than max_value. Otherwise, returns true and sets *output to the
216  // result. If the text is not from a Token of type TYPE_INTEGER originally
217  // parsed by a Tokenizer, the result is undefined (possibly an assert
218  // failure).
219  static bool ParseInteger(const std::string& text, uint64 max_value,
220  uint64* output);
221 
222  // Options ---------------------------------------------------------
223 
224  // Set true to allow floats to be suffixed with the letter 'f'. Tokens
225  // which would otherwise be integers but which have the 'f' suffix will be
226  // forced to be interpreted as floats. For all other purposes, the 'f' is
227  // ignored.
228  void set_allow_f_after_float(bool value) { allow_f_after_float_ = value; }
229 
230  // Valid values for set_comment_style().
232  // Line comments begin with "//", block comments are delimited by "/*" and
233  // "*/".
235  // Line comments begin with "#". No way to write block comments.
236  SH_COMMENT_STYLE
237  };
238 
239  // Sets the comment style.
240  void set_comment_style(CommentStyle style) { comment_style_ = style; }
241 
242  // Whether to require whitespace between a number and a field name.
243  // Default is true. Do not use this; for Google-internal cleanup only.
244  void set_require_space_after_number(bool require) {
245  require_space_after_number_ = require;
246  }
247 
248  // Whether to allow string literals to span multiple lines. Default is false.
249  // Do not use this; for Google-internal cleanup only.
250  void set_allow_multiline_strings(bool allow) {
251  allow_multiline_strings_ = allow;
252  }
253 
254  // External helper: validate an identifier.
255  static bool IsIdentifier(const std::string& text);
256 
257  // -----------------------------------------------------------------
258  private:
260 
261  Token current_; // Returned by current().
262  Token previous_; // Returned by previous().
263 
266 
267  char current_char_; // == buffer_[buffer_pos_], updated by NextChar().
268  const char* buffer_; // Current buffer returned from input_.
269  int buffer_size_; // Size of buffer_.
270  int buffer_pos_; // Current position within the buffer.
271  bool read_error_; // Did we previously encounter a read error?
272 
273  // Line and column number of current_char_ within the whole input stream.
274  int line_;
276 
277  // String to which text should be appended as we advance through it.
278  // Call RecordTo(&str) to start recording and StopRecording() to stop.
279  // E.g. StartToken() calls RecordTo(&current_.text). record_start_ is the
280  // position within the current buffer where recording started.
283 
284  // Options.
289 
290  // Since we count columns we need to interpret tabs somehow. We'll take
291  // the standard 8-character definition for lack of any way to do better.
292  // This must match the documentation of ColumnNumber.
293  static const int kTabWidth = 8;
294 
295  // -----------------------------------------------------------------
296  // Helper methods.
297 
298  // Consume this character and advance to the next one.
299  void NextChar();
300 
301  // Read a new buffer from the input.
302  void Refresh();
303 
304  inline void RecordTo(std::string* target);
305  inline void StopRecording();
306 
307  // Called when the current character is the first character of a new
308  // token (not including whitespace or comments).
309  inline void StartToken();
310  // Called when the current character is the first character after the
311  // end of the last token. After this returns, current_.text will
312  // contain all text consumed since StartToken() was called.
313  inline void EndToken();
314 
315  // Convenience method to add an error at the current line and column.
316  void AddError(const std::string& message) {
317  error_collector_->AddError(line_, column_, message);
318  }
319 
320  // -----------------------------------------------------------------
321  // The following four methods are used to consume tokens of specific
322  // types. They are actually used to consume all characters *after*
323  // the first, since the calling function consumes the first character
324  // in order to decide what kind of token is being read.
325 
326  // Read and consume a string, ending when the given delimiter is
327  // consumed.
328  void ConsumeString(char delimiter);
329 
330  // Read and consume a number, returning TYPE_FLOAT or TYPE_INTEGER
331  // depending on what was read. This needs to know if the first
332  // character was a zero in order to correctly recognize hex and octal
333  // numbers.
334  // It also needs to know if the first character was a . to parse floating
335  // point correctly.
336  TokenType ConsumeNumber(bool started_with_zero, bool started_with_dot);
337 
338  // Consume the rest of a line.
339  void ConsumeLineComment(std::string* content);
340  // Consume until "*/".
341  void ConsumeBlockComment(std::string* content);
342 
344  // Started a line comment.
346 
347  // Started a block comment.
349 
350  // Consumed a slash, then realized it wasn't a comment. current_ has
351  // been filled in with a slash token. The caller should return it.
353 
354  // We do not appear to be starting a comment here.
355  NO_COMMENT
356  };
357 
358  // If we're at the start of a new comment, consume it and return what kind
359  // of comment it is.
360  NextCommentStatus TryConsumeCommentStart();
361 
362  // -----------------------------------------------------------------
363  // These helper methods make the parsing code more readable. The
364  // "character classes" referred to are defined at the top of the .cc file.
365  // Basically it is a C++ class with one method:
366  // static bool InClass(char c);
367  // The method returns true if c is a member of this "class", like "Letter"
368  // or "Digit".
369 
370  // Returns true if the current character is of the given character
371  // class, but does not consume anything.
372  template <typename CharacterClass>
373  inline bool LookingAt();
374 
375  // If the current character is in the given class, consume it and return
376  // true. Otherwise return false.
377  // e.g. TryConsumeOne<Letter>()
378  template <typename CharacterClass>
379  inline bool TryConsumeOne();
380 
381  // Like above, but try to consume the specific character indicated.
382  inline bool TryConsume(char c);
383 
384  // Consume zero or more of the given character class.
385  template <typename CharacterClass>
386  inline void ConsumeZeroOrMore();
387 
388  // Consume one or more of the given character class or log the given
389  // error message.
390  // e.g. ConsumeOneOrMore<Digit>("Expected digits.");
391  template <typename CharacterClass>
392  inline void ConsumeOneOrMore(const char* error);
393 };
394 
395 // inline methods ====================================================
396 inline const Tokenizer::Token& Tokenizer::current() { return current_; }
397 
398 inline const Tokenizer::Token& Tokenizer::previous() { return previous_; }
399 
400 inline void Tokenizer::ParseString(const std::string& text,
401  std::string* output) {
402  output->clear();
403  ParseStringAppend(text, output);
404 }
405 
406 } // namespace io
407 } // namespace protobuf
408 } // namespace google
409 
410 #include <google/protobuf/port_undef.inc>
411 
412 #endif // GOOGLE_PROTOBUF_IO_TOKENIZER_H__
google::protobuf::io::Tokenizer::current
const Token & current()
Definition: tokenizer.h:396
google::protobuf::value
const Descriptor::ReservedRange value
Definition: src/google/protobuf/descriptor.h:1954
google::protobuf::io::Tokenizer::TYPE_FLOAT
@ TYPE_FLOAT
Definition: tokenizer.h:115
google::protobuf::io::Tokenizer::require_space_after_number_
bool require_space_after_number_
Definition: tokenizer.h:287
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS
#define GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeName)
Definition: macros.h:40
google::protobuf::io::Tokenizer::TYPE_IDENTIFIER
@ TYPE_IDENTIFIER
Definition: tokenizer.h:105
google::protobuf::io::Tokenizer::line_
int line_
Definition: tokenizer.h:274
google::protobuf::io::Tokenizer::TokenType
TokenType
Definition: tokenizer.h:101
google::protobuf::io::Tokenizer::set_require_space_after_number
void set_require_space_after_number(bool require)
Definition: tokenizer.h:244
input
std::string input
Definition: tokenizer_unittest.cc:197
generate_changelog.previous
previous
Definition: generate_changelog.py:55
google::protobuf::io::Tokenizer
Definition: tokenizer.h:93
google::protobuf::io::Tokenizer::SLASH_NOT_COMMENT
@ SLASH_NOT_COMMENT
Definition: tokenizer.h:352
google::protobuf::io::Tokenizer::previous_
Token previous_
Definition: tokenizer.h:262
google::protobuf::io::ColumnNumber
int ColumnNumber
Definition: tokenizer.h:55
google::protobuf::io::Tokenizer::set_comment_style
void set_comment_style(CommentStyle style)
Definition: tokenizer.h:240
google::protobuf::io::Tokenizer::set_allow_multiline_strings
void set_allow_multiline_strings(bool allow)
Definition: tokenizer.h:250
string
GLsizei const GLchar *const * string
Definition: glcorearb.h:3083
target
GLenum target
Definition: glcorearb.h:3739
error
Definition: cJSON.c:88
google::protobuf::io::Tokenizer::Token::line
int line
Definition: tokenizer.h:135
google::protobuf::io::Tokenizer::current_char_
char current_char_
Definition: tokenizer.h:267
line_
int line_
Definition: objectivec_helpers.cc:1468
google::protobuf::io::ErrorCollector::AddWarning
virtual void AddWarning(int line, ColumnNumber column, const std::string &message)
Definition: tokenizer.h:80
google::protobuf::io::Tokenizer::AddError
void AddError(const std::string &message)
Definition: tokenizer.h:316
google::protobuf::io::Tokenizer::NextCommentStatus
NextCommentStatus
Definition: tokenizer.h:343
google::protobuf.text_format.ParseFloat
def ParseFloat(text)
Definition: text_format.py:1686
google::protobuf::uint64
uint64_t uint64
Definition: protobuf/src/google/protobuf/stubs/port.h:156
prev_trailing_comments
const char * prev_trailing_comments
Definition: tokenizer_unittest.cc:525
detached_comments
const char * detached_comments[10]
Definition: tokenizer_unittest.cc:526
google::protobuf::io::Tokenizer::TYPE_STRING
@ TYPE_STRING
Definition: tokenizer.h:118
google::protobuf::io::Tokenizer::buffer_pos_
int buffer_pos_
Definition: tokenizer.h:270
google::protobuf::io::Tokenizer::ParseStringAppend
static void ParseStringAppend(const std::string &text, std::string *output)
Definition: tokenizer.cc:1034
google::protobuf::io::Tokenizer::buffer_
const char * buffer_
Definition: tokenizer.h:268
google::protobuf::io::Tokenizer::CommentStyle
CommentStyle
Definition: tokenizer.h:231
google::protobuf::io::ZeroCopyInputStream
Definition: zero_copy_stream.h:126
google::protobuf::io::Tokenizer::Token::type
TokenType type
Definition: tokenizer.h:128
google::protobuf::io::Tokenizer::Token::column
ColumnNumber column
Definition: tokenizer.h:136
google::protobuf::io::Tokenizer::Token::end_column
ColumnNumber end_column
Definition: tokenizer.h:137
error_collector_
MockErrorCollector error_collector_
Definition: importer_unittest.cc:129
google::protobuf::io::Tokenizer::TYPE_END
@ TYPE_END
Definition: tokenizer.h:103
common.h
google::protobuf::io::Tokenizer::current_
Token current_
Definition: tokenizer.h:261
google::protobuf::io::Tokenizer::column_
ColumnNumber column_
Definition: tokenizer.h:275
google::protobuf::io::Tokenizer::previous
const Token & previous()
Definition: tokenizer.h:398
google::protobuf::io::Tokenizer::ParseString
static void ParseString(const std::string &text, std::string *output)
Definition: tokenizer.h:400
google::protobuf::io::Tokenizer::comment_style_
CommentStyle comment_style_
Definition: tokenizer.h:286
google::protobuf::io::ErrorCollector
Definition: tokenizer.h:66
google::protobuf::io::Tokenizer::TYPE_START
@ TYPE_START
Definition: tokenizer.h:102
logging.h
google::protobuf::io::Tokenizer::set_allow_f_after_float
void set_allow_f_after_float(bool value)
Definition: tokenizer.h:228
google::protobuf::io::Tokenizer::record_start_
int record_start_
Definition: tokenizer.h:282
google::protobuf::io::Tokenizer::BLOCK_COMMENT
@ BLOCK_COMMENT
Definition: tokenizer.h:348
google::protobuf::io::Tokenizer::TYPE_INTEGER
@ TYPE_INTEGER
Definition: tokenizer.h:109
google::protobuf::io::Tokenizer::Token::text
std::string text
Definition: tokenizer.h:129
google::protobuf.text_format.ParseInteger
def ParseInteger(text, is_signed=False, is_long=False)
Definition: text_format.py:1631
google::protobuf::io::Tokenizer::CPP_COMMENT_STYLE
@ CPP_COMMENT_STYLE
Definition: tokenizer.h:234
google::protobuf::io::Tokenizer::Token
Definition: tokenizer.h:127
google::protobuf::io::Tokenizer::LINE_COMMENT
@ LINE_COMMENT
Definition: tokenizer.h:345
google::protobuf::io::Tokenizer::read_error_
bool read_error_
Definition: tokenizer.h:271
google::protobuf::io::Tokenizer::allow_f_after_float_
bool allow_f_after_float_
Definition: tokenizer.h:285
google::protobuf::io::Tokenizer::buffer_size_
int buffer_size_
Definition: tokenizer.h:269
google::protobuf::io::Tokenizer::record_target_
std::string * record_target_
Definition: tokenizer.h:281
value
GLsizei const GLfloat * value
Definition: glcorearb.h:3093
output
const upb_json_parsermethod const upb_symtab upb_sink * output
Definition: ruby/ext/google/protobuf_c/upb.h:10503
google::protobuf::io::Tokenizer::error_collector_
ErrorCollector * error_collector_
Definition: tokenizer.h:265
google::protobuf::io::ErrorCollector::ErrorCollector
ErrorCollector()
Definition: tokenizer.h:68
google::protobuf::io::Tokenizer::input_
ZeroCopyInputStream * input_
Definition: tokenizer.h:264
next_leading_comments
const char * next_leading_comments
Definition: tokenizer_unittest.cc:527
google
Definition: data_proto2_to_proto3_util.h:11
message
GLenum GLuint GLenum GLsizei const GLchar * message
Definition: glcorearb.h:2695
google::protobuf::io::Tokenizer::TYPE_SYMBOL
@ TYPE_SYMBOL
Definition: tokenizer.h:121
google::protobuf::io::Tokenizer::allow_multiline_strings_
bool allow_multiline_strings_
Definition: tokenizer.h:288


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:07:00