You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

tokenizer.h 23 kB

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