protobuf/src/google/protobuf/io/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 
41 #include <string>
42 #include <vector>
43 
44 #include <google/protobuf/stubs/common.h>
45 #include <google/protobuf/stubs/logging.h>
46 #include <google/protobuf/port_def.inc>
47 
48 namespace google {
49 namespace protobuf {
50 namespace io {
51 
52 class ZeroCopyInputStream; // zero_copy_stream.h
53 
54 // Defined in this file.
55 class ErrorCollector;
56 class Tokenizer;
57 
58 // By "column number", the proto compiler refers to a count of the number
59 // of bytes before a given byte, except that a tab character advances to
60 // the next multiple of 8 bytes. Note in particular that column numbers
61 // are zero-based, while many user interfaces use one-based column numbers.
62 typedef int ColumnNumber;
63 
64 // Abstract interface for an object which collects the errors that occur
65 // during parsing. A typical implementation might simply print the errors
66 // to stdout.
67 class PROTOBUF_EXPORT ErrorCollector {
68  public:
69  inline ErrorCollector() {}
70  virtual ~ErrorCollector();
71 
72  // Indicates that there was an error in the input at the given line and
73  // column numbers. The numbers are zero-based, so you may want to add
74  // 1 to each before printing them.
75  virtual void AddError(int line, ColumnNumber column,
76  const std::string& message) = 0;
77 
78  // Indicates that there was a warning in the input at the given line and
79  // column numbers. The numbers are zero-based, so you may want to add
80  // 1 to each before printing them.
81  virtual void AddWarning(int /* line */, ColumnNumber /* column */,
82  const std::string& /* message */) {}
83 
84  private:
86 };
87 
88 // This class converts a stream of raw text into a stream of tokens for
89 // the protocol definition parser to parse. The tokens recognized are
90 // similar to those that make up the C language; see the TokenType enum for
91 // precise descriptions. Whitespace and comments are skipped. By default,
92 // C- and C++-style comments are recognized, but other styles can be used by
93 // calling set_comment_style().
94 class PROTOBUF_EXPORT Tokenizer {
95  public:
96  // Construct a Tokenizer that reads and tokenizes text from the given
97  // input stream and writes errors to the given error_collector.
98  // The caller keeps ownership of input and error_collector.
99  Tokenizer(ZeroCopyInputStream* input, ErrorCollector* error_collector);
100  ~Tokenizer();
101 
102  enum TokenType {
103  TYPE_START, // Next() has not yet been called.
104  TYPE_END, // End of input reached. "text" is empty.
105 
106  TYPE_IDENTIFIER, // A sequence of letters, digits, and underscores, not
107  // starting with a digit. It is an error for a number
108  // to be followed by an identifier with no space in
109  // between.
110  TYPE_INTEGER, // A sequence of digits representing an integer. Normally
111  // the digits are decimal, but a prefix of "0x" indicates
112  // a hex number and a leading zero indicates octal, just
113  // like with C numeric literals. A leading negative sign
114  // is NOT included in the token; it's up to the parser to
115  // interpret the unary minus operator on its own.
116  TYPE_FLOAT, // A floating point literal, with a fractional part and/or
117  // an exponent. Always in decimal. Again, never
118  // negative.
119  TYPE_STRING, // A quoted sequence of escaped characters. Either single
120  // or double quotes can be used, but they must match.
121  // A string literal cannot cross a line break.
122  TYPE_SYMBOL, // Any other printable character, like '!' or '+'.
123  // Symbols are always a single character, so "!+$%" is
124  // four tokens.
125  TYPE_WHITESPACE, // A sequence of whitespace. This token type is only
126  // produced if report_whitespace() is true. It is not
127  // reported for whitespace within comments or strings.
128  TYPE_NEWLINE, // A newline (\n). This token type is only
129  // produced if report_whitespace() is true and
130  // report_newlines() is true. It is not reported for
131  // newlines in comments or strings.
132  };
133 
134  // Structure representing a token read from the token stream.
135  struct Token {
136  TokenType type;
137  std::string text; // The exact text of the token as it appeared in
138  // the input. e.g. tokens of TYPE_STRING will still
139  // be escaped and in quotes.
140 
141  // "line" and "column" specify the position of the first character of
142  // the token within the input stream. They are zero-based.
143  int line;
144  ColumnNumber column;
145  ColumnNumber end_column;
146  };
147 
148  // Get the current token. This is updated when Next() is called. Before
149  // the first call to Next(), current() has type TYPE_START and no contents.
150  const Token& current();
151 
152  // Return the previous token -- i.e. what current() returned before the
153  // previous call to Next().
154  const Token& previous();
155 
156  // Advance to the next token. Returns false if the end of the input is
157  // reached.
158  bool Next();
159 
160  // Like Next(), but also collects comments which appear between the previous
161  // and next tokens.
162  //
163  // Comments which appear to be attached to the previous token are stored
164  // in *prev_tailing_comments. Comments which appear to be attached to the
165  // next token are stored in *next_leading_comments. Comments appearing in
166  // between which do not appear to be attached to either will be added to
167  // detached_comments. Any of these parameters can be NULL to simply discard
168  // the comments.
169  //
170  // A series of line comments appearing on consecutive lines, with no other
171  // tokens appearing on those lines, will be treated as a single comment.
172  //
173  // Only the comment content is returned; comment markers (e.g. //) are
174  // stripped out. For block comments, leading whitespace and an asterisk will
175  // be stripped from the beginning of each line other than the first. Newlines
176  // are included in the output.
177  //
178  // Examples:
179  //
180  // optional int32 foo = 1; // Comment attached to foo.
181  // // Comment attached to bar.
182  // optional int32 bar = 2;
183  //
184  // optional string baz = 3;
185  // // Comment attached to baz.
186  // // Another line attached to baz.
187  //
188  // // Comment attached to qux.
189  // //
190  // // Another line attached to qux.
191  // optional double qux = 4;
192  //
193  // // Detached comment. This is not attached to qux or corge
194  // // because there are blank lines separating it from both.
195  //
196  // optional string corge = 5;
197  // /* Block comment attached
198  // * to corge. Leading asterisks
199  // * will be removed. */
200  // /* Block comment attached to
201  // * grault. */
202  // optional int32 grault = 6;
203  bool NextWithComments(std::string* prev_trailing_comments,
204  std::vector<std::string>* detached_comments,
206 
207  // Parse helpers ---------------------------------------------------
208 
209  // Parses a TYPE_FLOAT token. This never fails, so long as the text actually
210  // comes from a TYPE_FLOAT token parsed by Tokenizer. If it doesn't, the
211  // result is undefined (possibly an assert failure).
212  static double ParseFloat(const std::string& text);
213 
214  // Parses a TYPE_STRING token. This never fails, so long as the text actually
215  // comes from a TYPE_STRING token parsed by Tokenizer. If it doesn't, the
216  // result is undefined (possibly an assert failure).
217  static void ParseString(const std::string& text, std::string* output);
218 
219  // Identical to ParseString, but appends to output.
220  static void ParseStringAppend(const std::string& text, std::string* output);
221 
222  // Parses a TYPE_INTEGER token. Returns false if the result would be
223  // greater than max_value. Otherwise, returns true and sets *output to the
224  // result. If the text is not from a Token of type TYPE_INTEGER originally
225  // parsed by a Tokenizer, the result is undefined (possibly an assert
226  // failure).
227  static bool ParseInteger(const std::string& text, uint64_t max_value,
228  uint64_t* output);
229 
230  // Options ---------------------------------------------------------
231 
232  // Set true to allow floats to be suffixed with the letter 'f'. Tokens
233  // which would otherwise be integers but which have the 'f' suffix will be
234  // forced to be interpreted as floats. For all other purposes, the 'f' is
235  // ignored.
236  void set_allow_f_after_float(bool value) { allow_f_after_float_ = value; }
237 
238  // Valid values for set_comment_style().
240  // Line comments begin with "//", block comments are delimited by "/*" and
241  // "*/".
242  CPP_COMMENT_STYLE,
243  // Line comments begin with "#". No way to write block comments.
244  SH_COMMENT_STYLE
245  };
246 
247  // Sets the comment style.
248  void set_comment_style(CommentStyle style) { comment_style_ = style; }
249 
250  // Whether to require whitespace between a number and a field name.
251  // Default is true. Do not use this; for Google-internal cleanup only.
252  void set_require_space_after_number(bool require) {
253  require_space_after_number_ = require;
254  }
255 
256  // Whether to allow string literals to span multiple lines. Default is false.
257  // Do not use this; for Google-internal cleanup only.
258  void set_allow_multiline_strings(bool allow) {
259  allow_multiline_strings_ = allow;
260  }
261 
262  // If true, whitespace tokens are reported by Next().
263  // Note: `set_report_whitespace(false)` implies `set_report_newlines(false)`.
264  bool report_whitespace() const;
265  void set_report_whitespace(bool report);
266 
267  // If true, newline tokens are reported by Next().
268  // Note: `set_report_newlines(true)` implies `set_report_whitespace(true)`.
269  bool report_newlines() const;
270  void set_report_newlines(bool report);
271 
272  // External helper: validate an identifier.
273  static bool IsIdentifier(const std::string& text);
274 
275  // -----------------------------------------------------------------
276  private:
278 
279  Token current_; // Returned by current().
280  Token previous_; // Returned by previous().
281 
284 
285  char current_char_; // == buffer_[buffer_pos_], updated by NextChar().
286  const char* buffer_; // Current buffer returned from input_.
287  int buffer_size_; // Size of buffer_.
288  int buffer_pos_; // Current position within the buffer.
289  bool read_error_; // Did we previously encounter a read error?
290 
291  // Line and column number of current_char_ within the whole input stream.
292  int line_;
293  ColumnNumber column_;
294 
295  // String to which text should be appended as we advance through it.
296  // Call RecordTo(&str) to start recording and StopRecording() to stop.
297  // E.g. StartToken() calls RecordTo(&current_.text). record_start_ is the
298  // position within the current buffer where recording started.
299  std::string* record_target_;
300  int record_start_;
301 
302  // Options.
303  bool allow_f_after_float_;
304  CommentStyle comment_style_;
305  bool require_space_after_number_;
306  bool allow_multiline_strings_;
307  bool report_whitespace_ = false;
308  bool report_newlines_ = false;
309 
310  // Since we count columns we need to interpret tabs somehow. We'll take
311  // the standard 8-character definition for lack of any way to do better.
312  // This must match the documentation of ColumnNumber.
313  static const int kTabWidth = 8;
314 
315  // -----------------------------------------------------------------
316  // Helper methods.
317 
318  // Consume this character and advance to the next one.
319  void NextChar();
320 
321  // Read a new buffer from the input.
322  void Refresh();
323 
324  inline void RecordTo(std::string* target);
325  inline void StopRecording();
326 
327  // Called when the current character is the first character of a new
328  // token (not including whitespace or comments).
329  inline void StartToken();
330  // Called when the current character is the first character after the
331  // end of the last token. After this returns, current_.text will
332  // contain all text consumed since StartToken() was called.
333  inline void EndToken();
334 
335  // Convenience method to add an error at the current line and column.
336  void AddError(const std::string& message) {
337  error_collector_->AddError(line_, column_, message);
338  }
339 
340  // -----------------------------------------------------------------
341  // The following four methods are used to consume tokens of specific
342  // types. They are actually used to consume all characters *after*
343  // the first, since the calling function consumes the first character
344  // in order to decide what kind of token is being read.
345 
346  // Read and consume a string, ending when the given delimiter is
347  // consumed.
348  void ConsumeString(char delimiter);
349 
350  // Read and consume a number, returning TYPE_FLOAT or TYPE_INTEGER
351  // depending on what was read. This needs to know if the first
352  // character was a zero in order to correctly recognize hex and octal
353  // numbers.
354  // It also needs to know if the first character was a . to parse floating
355  // point correctly.
356  TokenType ConsumeNumber(bool started_with_zero, bool started_with_dot);
357 
358  // Consume the rest of a line.
359  void ConsumeLineComment(std::string* content);
360  // Consume until "*/".
361  void ConsumeBlockComment(std::string* content);
362 
364  // Started a line comment.
365  LINE_COMMENT,
366 
367  // Started a block comment.
368  BLOCK_COMMENT,
369 
370  // Consumed a slash, then realized it wasn't a comment. current_ has
371  // been filled in with a slash token. The caller should return it.
372  SLASH_NOT_COMMENT,
373 
374  // We do not appear to be starting a comment here.
375  NO_COMMENT
376  };
377 
378  // If we're at the start of a new comment, consume it and return what kind
379  // of comment it is.
380  NextCommentStatus TryConsumeCommentStart();
381 
382  // If we're looking at a TYPE_WHITESPACE token and `report_whitespace_` is
383  // true, consume it and return true.
384  bool TryConsumeWhitespace();
385 
386  // If we're looking at a TYPE_NEWLINE token and `report_newlines_` is true,
387  // consume it and return true.
388  bool TryConsumeNewline();
389 
390  // -----------------------------------------------------------------
391  // These helper methods make the parsing code more readable. The
392  // "character classes" referred to are defined at the top of the .cc file.
393  // Basically it is a C++ class with one method:
394  // static bool InClass(char c);
395  // The method returns true if c is a member of this "class", like "Letter"
396  // or "Digit".
397 
398  // Returns true if the current character is of the given character
399  // class, but does not consume anything.
400  template <typename CharacterClass>
401  inline bool LookingAt();
402 
403  // If the current character is in the given class, consume it and return
404  // true. Otherwise return false.
405  // e.g. TryConsumeOne<Letter>()
406  template <typename CharacterClass>
407  inline bool TryConsumeOne();
408 
409  // Like above, but try to consume the specific character indicated.
410  inline bool TryConsume(char c);
411 
412  // Consume zero or more of the given character class.
413  template <typename CharacterClass>
414  inline void ConsumeZeroOrMore();
415 
416  // Consume one or more of the given character class or log the given
417  // error message.
418  // e.g. ConsumeOneOrMore<Digit>("Expected digits.");
419  template <typename CharacterClass>
420  inline void ConsumeOneOrMore(const char* error);
421 };
422 
423 // inline methods ====================================================
424 inline const Tokenizer::Token& Tokenizer::current() { return current_; }
425 
426 inline const Tokenizer::Token& Tokenizer::previous() { return previous_; }
427 
428 inline void Tokenizer::ParseString(const std::string& text,
429  std::string* output) {
430  output->clear();
432 }
433 
434 } // namespace io
435 } // namespace protobuf
436 } // namespace google
437 
438 #include <google/protobuf/port_undef.inc>
439 
440 #endif // GOOGLE_PROTOBUF_IO_TOKENIZER_H__
check_grpcio_tools.content
content
Definition: check_grpcio_tools.py:26
prev_trailing_comments
const char * prev_trailing_comments
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer_unittest.cc:525
current_
Block * current_
Definition: protobuf/src/google/protobuf/descriptor.cc:1035
google::protobuf::io::Tokenizer::current
const Token & current()
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer.h:396
google::protobuf::value
const Descriptor::ReservedRange value
Definition: bloaty/third_party/protobuf/src/google/protobuf/descriptor.h:1954
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS
#define GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeName)
Definition: bloaty/third_party/protobuf/src/google/protobuf/stubs/macros.h:40
google::protobuf::io::Tokenizer::TokenType
TokenType
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer.h:101
google::protobuf::io::Tokenizer::set_require_space_after_number
void set_require_space_after_number(bool require)
Definition: protobuf/src/google/protobuf/io/tokenizer.h:252
grpc::protobuf::io::ZeroCopyInputStream
GRPC_CUSTOM_ZEROCOPYINPUTSTREAM ZeroCopyInputStream
Definition: include/grpcpp/impl/codegen/config_protobuf.h:101
generate_changelog.previous
previous
Definition: bloaty/third_party/protobuf/generate_changelog.py:55
google::protobuf::io::Tokenizer
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer.h:93
next_leading_comments
const char * next_leading_comments
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer_unittest.cc:527
google::protobuf::io::Tokenizer::previous_
Token previous_
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer.h:262
line_
int line_
Definition: bloaty/third_party/protobuf/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc:1468
google::protobuf::io::ColumnNumber
int ColumnNumber
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer.h:55
google::protobuf::io::Tokenizer::set_comment_style
void set_comment_style(CommentStyle style)
Definition: protobuf/src/google/protobuf/io/tokenizer.h:248
google::protobuf.text_format.ParseInteger
def ParseInteger(text, is_signed=False, is_long=False)
Definition: bloaty/third_party/protobuf/python/google/protobuf/text_format.py:1634
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
error
grpc_error_handle error
Definition: retry_filter.cc:499
google::protobuf
Definition: bloaty/third_party/protobuf/benchmarks/util/data_proto2_to_proto3_util.h:12
google::protobuf::io::Tokenizer::set_allow_multiline_strings
void set_allow_multiline_strings(bool allow)
Definition: protobuf/src/google/protobuf/io/tokenizer.h:258
absl::base_internal::Next
static AllocList * Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena)
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:453
message
char * message
Definition: libuv/docs/code/tty-gravity/main.c:12
input_
const uint8_t * input_
Definition: json_reader.cc:120
buffer_
static uint8 buffer_[kBufferSize]
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/coded_stream_unittest.cc:136
gen_server_registered_method_bad_client_test_body.text
def text
Definition: gen_server_registered_method_bad_client_test_body.py:50
gmock_output_test.output
output
Definition: bloaty/third_party/googletest/googlemock/test/gmock_output_test.py:175
google::protobuf::io::Tokenizer::AddError
void AddError(const std::string &message)
Definition: protobuf/src/google/protobuf/io/tokenizer.h:336
google::protobuf::io::Tokenizer::NextCommentStatus
NextCommentStatus
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer.h:343
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
io
google::protobuf::io::Tokenizer::ParseStringAppend
static void ParseStringAppend(const std::string &text, std::string *output)
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer.cc:1035
absl::strings_internal::ParseFloat
strings_internal::ParsedFloat ParseFloat(const char *begin, const char *end, chars_format format_flags)
Definition: abseil-cpp/absl/strings/internal/charconv_parse.cc:355
google::protobuf::io::Tokenizer::CommentStyle
CommentStyle
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer.h:231
google::protobuf::io::ZeroCopyInputStream
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/zero_copy_stream.h:126
google::protobuf::io::Tokenizer::TYPE_WHITESPACE
@ TYPE_WHITESPACE
Definition: protobuf/src/google/protobuf/io/tokenizer.h:125
detached_comments
const char * detached_comments[10]
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer_unittest.cc:526
google::protobuf::io::Tokenizer::current_
Token current_
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer.h:261
google::protobuf::io::Tokenizer::TYPE_NEWLINE
@ TYPE_NEWLINE
Definition: protobuf/src/google/protobuf/io/tokenizer.h:128
google::protobuf::io::Tokenizer::previous
const Token & previous()
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer.h:398
google::protobuf::io::Tokenizer::ParseString
static void ParseString(const std::string &text, std::string *output)
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer.h:400
google::protobuf::io::ErrorCollector
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer.h:66
regen-readme.line
line
Definition: regen-readme.py:30
google::protobuf::io::Tokenizer::set_allow_f_after_float
void set_allow_f_after_float(bool value)
Definition: protobuf/src/google/protobuf/io/tokenizer.h:236
google::protobuf::io::ErrorCollector::AddWarning
virtual void AddWarning(int, ColumnNumber, const std::string &)
Definition: protobuf/src/google/protobuf/io/tokenizer.h:81
input
std::string input
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer_unittest.cc:197
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
google::protobuf::io::ErrorCollector::ErrorCollector
ErrorCollector()
Definition: protobuf/src/google/protobuf/io/tokenizer.h:69
error_collector_
MockErrorCollector error_collector_
Definition: bloaty/third_party/protobuf/src/google/protobuf/compiler/importer_unittest.cc:129
setup.target
target
Definition: third_party/bloaty/third_party/protobuf/python/setup.py:179
google
Definition: bloaty/third_party/protobuf/benchmarks/util/data_proto2_to_proto3_util.h:11


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:39