Line data Source code
1 : // lex.cc -- Go frontend lexer.
2 :
3 : // Copyright 2009 The Go Authors. All rights reserved.
4 : // Use of this source code is governed by a BSD-style
5 : // license that can be found in the LICENSE file.
6 :
7 : #include "go-system.h"
8 : #include "go-diagnostics.h"
9 :
10 : #include "lex.h"
11 :
12 : // Manage mapping from keywords to the Keyword codes.
13 :
14 : class Keywords
15 : {
16 : public:
17 : // The structure which maps keywords to codes.
18 : struct Mapping
19 : {
20 : // Keyword string.
21 : const char* keystring;
22 : // Keyword code.
23 : Keyword keycode;
24 : };
25 :
26 : // Return the parsecode corresponding to KEYSTRING, or
27 : // KEYWORD_INVALID if it is not a keyword.
28 : Keyword
29 : keyword_to_code(const char* keyword, size_t len) const;
30 :
31 : // Return the string for a keyword.
32 : const char*
33 : keyword_to_string(Keyword) const;
34 :
35 : private:
36 : static const Mapping mapping_[];
37 : static const int count_;
38 : };
39 :
40 : // Mapping from keyword string to keyword code. This array must be
41 : // kept in sorted order, and the order must match the Keyword enum.
42 : // Strings are looked up using bsearch.
43 :
44 : const Keywords::Mapping
45 : Keywords::mapping_[] =
46 : {
47 : { NULL, KEYWORD_INVALID },
48 : { "__asm__", KEYWORD_ASM },
49 : { "break", KEYWORD_BREAK },
50 : { "case", KEYWORD_CASE },
51 : { "chan", KEYWORD_CHAN },
52 : { "const", KEYWORD_CONST },
53 : { "continue", KEYWORD_CONTINUE },
54 : { "default", KEYWORD_DEFAULT },
55 : { "defer", KEYWORD_DEFER },
56 : { "else", KEYWORD_ELSE },
57 : { "fallthrough", KEYWORD_FALLTHROUGH },
58 : { "for", KEYWORD_FOR },
59 : { "func", KEYWORD_FUNC },
60 : { "go", KEYWORD_GO },
61 : { "goto", KEYWORD_GOTO },
62 : { "if", KEYWORD_IF },
63 : { "import", KEYWORD_IMPORT },
64 : { "interface", KEYWORD_INTERFACE },
65 : { "map", KEYWORD_MAP },
66 : { "package", KEYWORD_PACKAGE },
67 : { "range", KEYWORD_RANGE },
68 : { "return", KEYWORD_RETURN },
69 : { "select", KEYWORD_SELECT },
70 : { "struct", KEYWORD_STRUCT },
71 : { "switch", KEYWORD_SWITCH },
72 : { "type", KEYWORD_TYPE },
73 : { "var", KEYWORD_VAR }
74 : };
75 :
76 : // Number of entries in the map.
77 :
78 : const int Keywords::count_ =
79 : sizeof(Keywords::mapping_) / sizeof(Keywords::mapping_[0]);
80 :
81 : // Comparison function passed to bsearch.
82 :
83 : extern "C"
84 : {
85 :
86 : struct Keywords_search_key
87 : {
88 : const char* str;
89 : size_t len;
90 : };
91 :
92 : static int
93 33463102 : keyword_compare(const void* keyv, const void* mapv)
94 : {
95 33463102 : const Keywords_search_key* key =
96 : static_cast<const Keywords_search_key*>(keyv);
97 33463102 : const Keywords::Mapping* map =
98 : static_cast<const Keywords::Mapping*>(mapv);
99 33463102 : if (map->keystring == NULL)
100 : return 1;
101 32236845 : int i = strncmp(key->str, map->keystring, key->len);
102 32236845 : if (i != 0)
103 : return i;
104 2322740 : if (map->keystring[key->len] != '\0')
105 1212894 : return -1;
106 : return 0;
107 : }
108 :
109 : } // End extern "C".
110 :
111 : // Convert a string to a keyword code. Return KEYWORD_INVALID if the
112 : // string is not a keyword.
113 :
114 : Keyword
115 6995588 : Keywords::keyword_to_code(const char* keyword, size_t len) const
116 : {
117 6995588 : Keywords_search_key key;
118 6995588 : key.str = keyword;
119 6995588 : key.len = len;
120 6995588 : void* mapv = bsearch(&key,
121 : this->mapping_,
122 : this->count_,
123 : sizeof(this->mapping_[0]),
124 : keyword_compare);
125 6995588 : if (mapv == NULL)
126 : return KEYWORD_INVALID;
127 1109846 : Mapping* map = static_cast<Mapping*>(mapv);
128 1109846 : return map->keycode;
129 : }
130 :
131 : // Convert a keyword code to a string.
132 :
133 : const char*
134 0 : Keywords::keyword_to_string(Keyword code) const
135 : {
136 0 : go_assert(code > KEYWORD_INVALID && code < this->count_);
137 0 : const Mapping* map = &this->mapping_[code];
138 0 : go_assert(map->keycode == code);
139 0 : return map->keystring;
140 : }
141 :
142 : // There is one instance of the Keywords class.
143 :
144 : static Keywords keywords;
145 :
146 : // Class Token.
147 :
148 : // Make a general token.
149 :
150 21766439 : Token::Token(Classification classification, Location location)
151 21766439 : : classification_(classification), location_(location)
152 : {
153 21766439 : }
154 :
155 : // Destroy a token.
156 :
157 23096849 : Token::~Token()
158 : {
159 23096849 : this->clear();
160 23096849 : }
161 :
162 : // Clear a token--release memory.
163 :
164 : void
165 44837874 : Token::clear()
166 : {
167 44837874 : if (this->classification_ == TOKEN_INTEGER
168 44837874 : || this->classification_ == TOKEN_CHARACTER)
169 3932109 : mpz_clear(this->u_.integer_value);
170 40905765 : else if (this->classification_ == TOKEN_FLOAT
171 40905765 : || this->classification_ == TOKEN_IMAGINARY)
172 59121 : mpfr_clear(this->u_.float_value);
173 44837874 : }
174 :
175 : // Construct a token.
176 :
177 1330410 : Token::Token(const Token& tok)
178 1330410 : : classification_(tok.classification_), location_(tok.location_)
179 : {
180 1330410 : switch (this->classification_)
181 : {
182 : case TOKEN_INVALID:
183 : case TOKEN_EOF:
184 : break;
185 0 : case TOKEN_KEYWORD:
186 0 : this->u_.keyword = tok.u_.keyword;
187 0 : break;
188 0 : case TOKEN_IDENTIFIER:
189 0 : case TOKEN_STRING:
190 0 : this->u_.string_value = tok.u_.string_value;
191 0 : break;
192 0 : case TOKEN_OPERATOR:
193 0 : this->u_.op = tok.u_.op;
194 0 : break;
195 1310703 : case TOKEN_CHARACTER:
196 1310703 : case TOKEN_INTEGER:
197 1310703 : mpz_init_set(this->u_.integer_value, tok.u_.integer_value);
198 1310703 : break;
199 19707 : case TOKEN_FLOAT:
200 19707 : case TOKEN_IMAGINARY:
201 19707 : mpfr_init_set(this->u_.float_value, tok.u_.float_value, MPFR_RNDN);
202 19707 : break;
203 0 : default:
204 0 : go_unreachable();
205 : }
206 1330410 : }
207 :
208 : // Assign to a token.
209 :
210 : Token&
211 21741025 : Token::operator=(const Token& tok)
212 : {
213 21741025 : this->clear();
214 21741025 : this->classification_ = tok.classification_;
215 21741025 : this->location_ = tok.location_;
216 21741025 : switch (tok.classification_)
217 : {
218 : case TOKEN_INVALID:
219 : case TOKEN_EOF:
220 : break;
221 1109846 : case TOKEN_KEYWORD:
222 1109846 : this->u_.keyword = tok.u_.keyword;
223 1109846 : break;
224 7643127 : case TOKEN_IDENTIFIER:
225 7643127 : this->u_.identifier_value.name = tok.u_.identifier_value.name;
226 7643127 : this->u_.identifier_value.is_exported =
227 7643127 : tok.u_.identifier_value.is_exported;
228 7643127 : break;
229 460495 : case TOKEN_STRING:
230 460495 : this->u_.string_value = tok.u_.string_value;
231 460495 : break;
232 11184438 : case TOKEN_OPERATOR:
233 11184438 : this->u_.op = tok.u_.op;
234 11184438 : break;
235 1310703 : case TOKEN_CHARACTER:
236 1310703 : case TOKEN_INTEGER:
237 1310703 : mpz_init_set(this->u_.integer_value, tok.u_.integer_value);
238 1310703 : break;
239 19707 : case TOKEN_FLOAT:
240 19707 : case TOKEN_IMAGINARY:
241 19707 : mpfr_init_set(this->u_.float_value, tok.u_.float_value, MPFR_RNDN);
242 19707 : break;
243 0 : default:
244 0 : go_unreachable();
245 : }
246 21741025 : return *this;
247 : }
248 :
249 : // Print the token for debugging.
250 :
251 : void
252 0 : Token::print(FILE* file) const
253 : {
254 0 : switch (this->classification_)
255 : {
256 0 : case TOKEN_INVALID:
257 0 : fprintf(file, "invalid");
258 0 : break;
259 0 : case TOKEN_EOF:
260 0 : fprintf(file, "EOF");
261 0 : break;
262 0 : case TOKEN_KEYWORD:
263 0 : fprintf(file, "keyword %s", keywords.keyword_to_string(this->u_.keyword));
264 0 : break;
265 0 : case TOKEN_IDENTIFIER:
266 0 : fprintf(file, "identifier \"%s\"", this->u_.string_value->c_str());
267 0 : break;
268 0 : case TOKEN_STRING:
269 0 : fprintf(file, "quoted string \"%s\"", this->u_.string_value->c_str());
270 0 : break;
271 0 : case TOKEN_CHARACTER:
272 0 : fprintf(file, "character ");
273 0 : mpz_out_str(file, 10, this->u_.integer_value);
274 0 : break;
275 0 : case TOKEN_INTEGER:
276 0 : fprintf(file, "integer ");
277 0 : mpz_out_str(file, 10, this->u_.integer_value);
278 0 : break;
279 0 : case TOKEN_FLOAT:
280 0 : fprintf(file, "float ");
281 0 : mpfr_out_str(file, 10, 0, this->u_.float_value, MPFR_RNDN);
282 0 : break;
283 0 : case TOKEN_IMAGINARY:
284 0 : fprintf(file, "imaginary ");
285 0 : mpfr_out_str(file, 10, 0, this->u_.float_value, MPFR_RNDN);
286 0 : break;
287 0 : case TOKEN_OPERATOR:
288 0 : fprintf(file, "operator ");
289 0 : switch (this->u_.op)
290 : {
291 0 : case OPERATOR_INVALID:
292 0 : fprintf(file, "invalid");
293 0 : break;
294 0 : case OPERATOR_OROR:
295 0 : fprintf(file, "||");
296 0 : break;
297 0 : case OPERATOR_ANDAND:
298 0 : fprintf(file, "&&");
299 0 : break;
300 0 : case OPERATOR_EQEQ:
301 0 : fprintf(file, "==");
302 0 : break;
303 0 : case OPERATOR_NOTEQ:
304 0 : fprintf(file, "!=");
305 0 : break;
306 0 : case OPERATOR_LT:
307 0 : fprintf(file, "<");
308 0 : break;
309 0 : case OPERATOR_LE:
310 0 : fprintf(file, "<=");
311 0 : break;
312 0 : case OPERATOR_GT:
313 0 : fprintf(file, ">");
314 0 : break;
315 0 : case OPERATOR_GE:
316 0 : fprintf(file, ">=");
317 0 : break;
318 0 : case OPERATOR_PLUS:
319 0 : fprintf(file, "+");
320 0 : break;
321 0 : case OPERATOR_MINUS:
322 0 : fprintf(file, "-");
323 0 : break;
324 0 : case OPERATOR_OR:
325 0 : fprintf(file, "|");
326 0 : break;
327 0 : case OPERATOR_XOR:
328 0 : fprintf(file, "^");
329 0 : break;
330 0 : case OPERATOR_MULT:
331 0 : fprintf(file, "*");
332 0 : break;
333 0 : case OPERATOR_DIV:
334 0 : fprintf(file, "/");
335 0 : break;
336 0 : case OPERATOR_MOD:
337 0 : fprintf(file, "%%");
338 0 : break;
339 0 : case OPERATOR_LSHIFT:
340 0 : fprintf(file, "<<");
341 0 : break;
342 0 : case OPERATOR_RSHIFT:
343 0 : fprintf(file, ">>");
344 0 : break;
345 0 : case OPERATOR_AND:
346 0 : fprintf(file, "&");
347 0 : break;
348 0 : case OPERATOR_BITCLEAR:
349 0 : fprintf(file, "&^");
350 0 : break;
351 0 : case OPERATOR_NOT:
352 0 : fprintf(file, "!");
353 0 : break;
354 0 : case OPERATOR_CHANOP:
355 0 : fprintf(file, "<-");
356 0 : break;
357 0 : case OPERATOR_EQ:
358 0 : fprintf(file, "=");
359 0 : break;
360 0 : case OPERATOR_PLUSEQ:
361 0 : fprintf(file, "+=");
362 0 : break;
363 0 : case OPERATOR_MINUSEQ:
364 0 : fprintf(file, "-=");
365 0 : break;
366 0 : case OPERATOR_OREQ:
367 0 : fprintf(file, "|=");
368 0 : break;
369 0 : case OPERATOR_XOREQ:
370 0 : fprintf(file, "^=");
371 0 : break;
372 0 : case OPERATOR_MULTEQ:
373 0 : fprintf(file, "*=");
374 0 : break;
375 0 : case OPERATOR_DIVEQ:
376 0 : fprintf(file, "/=");
377 0 : break;
378 0 : case OPERATOR_MODEQ:
379 0 : fprintf(file, "%%=");
380 0 : break;
381 0 : case OPERATOR_LSHIFTEQ:
382 0 : fprintf(file, "<<=");
383 0 : break;
384 0 : case OPERATOR_RSHIFTEQ:
385 0 : fprintf(file, ">>=");
386 0 : break;
387 0 : case OPERATOR_ANDEQ:
388 0 : fprintf(file, "&=");
389 0 : break;
390 0 : case OPERATOR_BITCLEAREQ:
391 0 : fprintf(file, "&^=");
392 0 : break;
393 0 : case OPERATOR_PLUSPLUS:
394 0 : fprintf(file, "++");
395 0 : break;
396 0 : case OPERATOR_MINUSMINUS:
397 0 : fprintf(file, "--");
398 0 : break;
399 0 : case OPERATOR_COLON:
400 0 : fprintf(file, ":");
401 0 : break;
402 0 : case OPERATOR_COLONEQ:
403 0 : fprintf(file, ":=");
404 0 : break;
405 0 : case OPERATOR_SEMICOLON:
406 0 : fprintf(file, ";");
407 0 : break;
408 0 : case OPERATOR_DOT:
409 0 : fprintf(file, ".");
410 0 : break;
411 0 : case OPERATOR_COMMA:
412 0 : fprintf(file, ",");
413 0 : break;
414 0 : case OPERATOR_LPAREN:
415 0 : fprintf(file, "(");
416 0 : break;
417 0 : case OPERATOR_RPAREN:
418 0 : fprintf(file, ")");
419 0 : break;
420 0 : case OPERATOR_LCURLY:
421 0 : fprintf(file, "{");
422 0 : break;
423 0 : case OPERATOR_RCURLY:
424 0 : fprintf(file, "}");
425 0 : break;
426 0 : case OPERATOR_LSQUARE:
427 0 : fprintf(file, "[");
428 0 : break;
429 0 : case OPERATOR_RSQUARE:
430 0 : fprintf(file, "]");
431 0 : break;
432 0 : default:
433 0 : go_unreachable();
434 : }
435 : break;
436 0 : default:
437 0 : go_unreachable();
438 : }
439 0 : }
440 :
441 : // Class Lex.
442 :
443 12707 : Lex::Lex(const char* input_file_name, FILE* input_file, Linemap* linemap)
444 12707 : : input_file_name_(input_file_name), input_file_(input_file),
445 12707 : linemap_(linemap), linebuf_(NULL), linebufsize_(120), linesize_(0),
446 12707 : lineoff_(0), lineno_(0), add_semi_at_eol_(false), pragmas_(0),
447 12707 : extern_(), linknames_(NULL)
448 : {
449 12707 : this->linebuf_ = new char[this->linebufsize_];
450 12707 : this->linemap_->start_file(input_file_name, 0);
451 12707 : }
452 :
453 12707 : Lex::~Lex()
454 : {
455 12707 : delete[] this->linebuf_;
456 12707 : }
457 :
458 : // Read a new line from the file.
459 :
460 : ssize_t
461 3771777 : Lex::get_line()
462 : {
463 3771777 : char* buf = this->linebuf_;
464 3771777 : size_t size = this->linebufsize_;
465 :
466 3771777 : FILE* file = this->input_file_;
467 3771777 : size_t cur = 0;
468 118965754 : while (true)
469 : {
470 118965754 : int c = getc(file);
471 118965754 : if (c == EOF)
472 : {
473 12722 : if (cur == 0)
474 : return -1;
475 : break;
476 : }
477 118953032 : if (cur + 1 >= size)
478 : {
479 2790 : size_t ns = 2 * size + 1;
480 2790 : if (ns < size || static_cast<ssize_t>(ns) < 0)
481 0 : go_error_at(this->location(), "out of memory");
482 2790 : char* nb = new char[ns];
483 2790 : memcpy(nb, buf, cur);
484 2790 : delete[] buf;
485 2790 : buf = nb;
486 2790 : size = ns;
487 : }
488 118953032 : buf[cur] = c;
489 118953032 : ++cur;
490 :
491 118953032 : if (c == '\n')
492 : break;
493 : }
494 :
495 3759062 : buf[cur] = '\0';
496 :
497 3759062 : this->linebuf_ = buf;
498 3759062 : this->linebufsize_ = size;
499 :
500 3759062 : return cur;
501 : }
502 :
503 : // See if we need to read a new line. Return true if there is a new
504 : // line, false if we are at EOF.
505 :
506 : bool
507 21790648 : Lex::require_line()
508 : {
509 21790648 : if (this->lineoff_ < this->linesize_)
510 : return true;
511 :
512 3771777 : ssize_t got = this->get_line();
513 3771777 : if (got < 0)
514 : return false;
515 3759062 : ++this->lineno_;
516 3759062 : this->linesize_= got;
517 3759062 : this->lineoff_ = 0;
518 :
519 3759062 : this->linemap_->start_line(this->lineno_, this->linesize_);
520 :
521 3759062 : return true;
522 : }
523 :
524 : // Get the current location.
525 :
526 : Location
527 19844969 : Lex::location() const
528 : {
529 19844969 : return this->linemap_->get_location(this->lineoff_ + 1);
530 : }
531 :
532 : // Get a location slightly before the current one. This is used for
533 : // slightly more efficient handling of operator tokens.
534 :
535 : Location
536 10941373 : Lex::earlier_location(int chars) const
537 : {
538 10941373 : return this->linemap_->get_location(this->lineoff_ + 1 - chars);
539 : }
540 :
541 : // Get the next token.
542 :
543 : Token
544 19740847 : Lex::next_token()
545 : {
546 19740847 : bool saw_cpp_comment = false;
547 23661419 : while (true)
548 : {
549 21701133 : if (!this->require_line())
550 : {
551 12715 : bool add_semi_at_eol = this->add_semi_at_eol_;
552 12715 : this->add_semi_at_eol_ = false;
553 12715 : if (add_semi_at_eol)
554 6 : return this->make_operator(OPERATOR_SEMICOLON, 1);
555 12709 : return this->make_eof_token();
556 : }
557 :
558 21688418 : if (!saw_cpp_comment)
559 21012890 : this->extern_.clear();
560 21688418 : saw_cpp_comment = false;
561 :
562 21688418 : const char* p = this->linebuf_ + this->lineoff_;
563 21688418 : const char* pend = this->linebuf_ + this->linesize_;
564 :
565 32496680 : while (p < pend)
566 : {
567 30536394 : unsigned char cc = *p;
568 30536394 : switch (cc)
569 : {
570 8783350 : case ' ': case '\t': case '\r':
571 8783350 : ++p;
572 : // Skip whitespace quickly.
573 11685803 : while (*p == ' ' || *p == '\t' || *p == '\r')
574 2902453 : ++p;
575 : break;
576 :
577 3003163 : case '\n':
578 3003163 : {
579 3003163 : ++p;
580 3003163 : bool add_semi_at_eol = this->add_semi_at_eol_;
581 3003163 : this->add_semi_at_eol_ = false;
582 3003163 : if (add_semi_at_eol)
583 : {
584 1718546 : this->lineoff_ = p - this->linebuf_;
585 1718546 : return this->make_operator(OPERATOR_SEMICOLON, 1);
586 : }
587 : }
588 : break;
589 :
590 751478 : case '/':
591 751478 : if (p[1] == '/')
592 : {
593 731023 : this->lineoff_ = p + 2 - this->linebuf_;
594 731023 : this->skip_cpp_comment();
595 731023 : p = pend;
596 731023 : if (p[-1] == '\n' && this->add_semi_at_eol_)
597 55358 : --p;
598 : saw_cpp_comment = true;
599 : }
600 20455 : else if (p[1] == '*')
601 : {
602 9291 : this->lineoff_ = p + 2 - this->linebuf_;
603 9291 : Location location = this->location();
604 9291 : bool found_newline = false;
605 9291 : if (!this->skip_c_comment(&found_newline))
606 25 : return Token::make_invalid_token(location);
607 9291 : if (found_newline && this->add_semi_at_eol_)
608 : {
609 25 : this->add_semi_at_eol_ = false;
610 25 : return this->make_operator(OPERATOR_SEMICOLON, 1);
611 : }
612 9266 : p = this->linebuf_ + this->lineoff_;
613 9266 : pend = this->linebuf_ + this->linesize_;
614 : }
615 11164 : else if (p[1] == '=')
616 : {
617 407 : this->add_semi_at_eol_ = false;
618 407 : this->lineoff_ = p + 2 - this->linebuf_;
619 407 : return this->make_operator(OPERATOR_DIVEQ, 2);
620 : }
621 : else
622 : {
623 10757 : this->add_semi_at_eol_ = false;
624 10757 : this->lineoff_ = p + 1 - this->linebuf_;
625 10757 : return this->make_operator(OPERATOR_DIV, 1);
626 : }
627 : break;
628 :
629 6995759 : case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
630 6995759 : case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
631 6995759 : case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
632 6995759 : case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
633 6995759 : case 'Y': case 'Z':
634 6995759 : case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
635 6995759 : case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
636 6995759 : case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
637 6995759 : case 's': case 't': case 'u': case 'v': case 'w': case 'x':
638 6995759 : case 'y': case 'z':
639 6995759 : case '_':
640 6995759 : this->lineoff_ = p - this->linebuf_;
641 6995759 : return this->gather_identifier();
642 :
643 1281217 : case '0': case '1': case '2': case '3': case '4':
644 1281217 : case '5': case '6': case '7': case '8': case '9':
645 1281217 : this->add_semi_at_eol_ = true;
646 1281217 : this->lineoff_ = p - this->linebuf_;
647 1281217 : return this->gather_number();
648 :
649 49036 : case '\'':
650 49036 : this->add_semi_at_eol_ = true;
651 49036 : this->lineoff_ = p - this->linebuf_;
652 49036 : return this->gather_character();
653 :
654 432554 : case '"':
655 432554 : this->add_semi_at_eol_ = true;
656 432554 : this->lineoff_ = p - this->linebuf_;
657 432554 : return this->gather_string();
658 :
659 27941 : case '`':
660 27941 : this->add_semi_at_eol_ = true;
661 27941 : this->lineoff_ = p - this->linebuf_;
662 27941 : return this->gather_raw_string();
663 :
664 238018 : case '<':
665 238018 : case '>':
666 238018 : case '&':
667 238018 : if (p + 2 < pend)
668 : {
669 238018 : this->add_semi_at_eol_ = false;
670 238018 : Operator op = this->three_character_operator(cc, p[1], p[2]);
671 238018 : if (op != OPERATOR_INVALID)
672 : {
673 2273 : this->lineoff_ = p + 3 - this->linebuf_;
674 2273 : return this->make_operator(op, 3);
675 : }
676 : }
677 : // Fall through.
678 8190527 : case '|':
679 8190527 : case '=':
680 8190527 : case '!':
681 8190527 : case '+':
682 8190527 : case '-':
683 8190527 : case '^':
684 8190527 : case '*':
685 : // '/' handled above.
686 8190527 : case '%':
687 8190527 : case ':':
688 8190527 : case ';':
689 8190527 : case ',':
690 8190527 : case '(': case ')':
691 8190527 : case '{': case '}':
692 8190527 : case '[': case ']':
693 8190527 : {
694 8190527 : this->add_semi_at_eol_ = false;
695 8190527 : Operator op = this->two_character_operator(cc, p[1]);
696 8190527 : int chars;
697 8190527 : if (op != OPERATOR_INVALID)
698 : {
699 645728 : ++p;
700 645728 : chars = 2;
701 : }
702 : else
703 : {
704 7544799 : op = this->one_character_operator(cc);
705 7544799 : chars = 1;
706 : }
707 8190527 : this->lineoff_ = p + 1 - this->linebuf_;
708 8190527 : return this->make_operator(op, chars);
709 : }
710 :
711 1018989 : case '.':
712 1018989 : if (p[1] >= '0' && p[1] <= '9')
713 : {
714 157 : this->add_semi_at_eol_ = true;
715 157 : this->lineoff_ = p - this->linebuf_;
716 157 : return this->gather_number();
717 : }
718 1018832 : if (p[1] == '.' && p[2] == '.')
719 : {
720 8216 : this->add_semi_at_eol_ = false;
721 8216 : this->lineoff_ = p + 3 - this->linebuf_;
722 8216 : return this->make_operator(OPERATOR_ELLIPSIS, 3);
723 : }
724 1010616 : this->add_semi_at_eol_ = false;
725 1010616 : this->lineoff_ = p + 1 - this->linebuf_;
726 1010616 : return this->make_operator(OPERATOR_DOT, 1);
727 :
728 107 : default:
729 107 : {
730 107 : unsigned int ci;
731 107 : bool issued_error;
732 107 : this->lineoff_ = p - this->linebuf_;
733 107 : const char *pnext = this->advance_one_utf8_char(p, &ci,
734 : &issued_error);
735 :
736 : // Ignore byte order mark at start of file.
737 107 : if (ci == 0xfeff)
738 : {
739 : p = pnext;
740 6 : break;
741 : }
742 :
743 105 : if (Lex::is_unicode_letter(ci))
744 101 : return this->gather_identifier();
745 :
746 4 : if (!issued_error && Lex::is_unicode_digit(ci))
747 : {
748 1 : go_error_at(this->location(),
749 : "identifier cannot begin with digit");
750 1 : issued_error = true;
751 : }
752 :
753 4 : if (!issued_error)
754 1 : go_error_at(this->location(),
755 : "invalid character 0x%x in input file",
756 : ci);
757 :
758 : p = pend;
759 :
760 : break;
761 : }
762 : }
763 : }
764 :
765 1960286 : this->lineoff_ = p - this->linebuf_;
766 1960286 : }
767 : }
768 :
769 : // Fetch one UTF-8 character from a string. Set *VALUE to the value.
770 : // Return the number of bytes read from the string. Returns 0 if the
771 : // string does not point to a valid UTF-8 character.
772 :
773 : int
774 44245316 : Lex::fetch_char(const char* p, unsigned int* value)
775 : {
776 44245316 : unsigned char c = *p;
777 44245316 : if (c <= 0x7f)
778 : {
779 43199753 : *value = c;
780 43199753 : return 1;
781 : }
782 1045563 : else if ((c & 0xe0) == 0xc0
783 25809 : && (p[1] & 0xc0) == 0x80)
784 : {
785 25807 : *value = (((c & 0x1f) << 6)
786 25807 : + (p[1] & 0x3f));
787 25807 : if (*value <= 0x7f)
788 : {
789 1 : *value = 0xfffd;
790 1 : return 0;
791 : }
792 : return 2;
793 : }
794 1019756 : else if ((c & 0xf0) == 0xe0
795 1018925 : && (p[1] & 0xc0) == 0x80
796 1018924 : && (p[2] & 0xc0) == 0x80)
797 : {
798 1018923 : *value = (((c & 0xf) << 12)
799 1018923 : + ((p[1] & 0x3f) << 6)
800 1018923 : + (p[2] & 0x3f));
801 1018923 : if (*value <= 0x7ff)
802 : {
803 0 : *value = 0xfffd;
804 0 : return 0;
805 : }
806 : return 3;
807 : }
808 833 : else if ((c & 0xf8) == 0xf0
809 821 : && (p[1] & 0xc0) == 0x80
810 821 : && (p[2] & 0xc0) == 0x80
811 821 : && (p[3] & 0xc0) == 0x80)
812 : {
813 821 : *value = (((c & 0x7) << 18)
814 821 : + ((p[1] & 0x3f) << 12)
815 821 : + ((p[2] & 0x3f) << 6)
816 821 : + (p[3] & 0x3f));
817 821 : if (*value <= 0xffff)
818 : {
819 0 : *value = 0xfffd;
820 0 : return 0;
821 : }
822 : return 4;
823 : }
824 : else
825 : {
826 : /* Invalid encoding. Return the Unicode replacement
827 : character. */
828 12 : *value = 0xfffd;
829 12 : return 0;
830 : }
831 : }
832 :
833 : // Advance one UTF-8 character. Return the pointer beyond the
834 : // character. Set *VALUE to the value. Set *ISSUED_ERROR if an error
835 : // was issued.
836 :
837 : const char*
838 43840707 : Lex::advance_one_utf8_char(const char* p, unsigned int* value,
839 : bool* issued_error)
840 : {
841 43840707 : *issued_error = false;
842 :
843 43840707 : if (*p == '\0')
844 : {
845 7 : go_error_at(this->location(), "invalid NUL byte");
846 7 : *issued_error = true;
847 7 : *value = 0;
848 7 : return p + 1;
849 : }
850 :
851 43840700 : int adv = Lex::fetch_char(p, value);
852 43840700 : if (adv == 0)
853 : {
854 9 : go_error_at(this->location(), "invalid UTF-8 encoding");
855 9 : *issued_error = true;
856 9 : return p + 1;
857 : }
858 :
859 : // Warn about byte order mark, except at start of file.
860 43840691 : if (*value == 0xfeff && (this->lineno_ != 1 || this->lineoff_ != 0))
861 : {
862 4 : go_error_at(this->location(), "Unicode (UTF-8) BOM in middle of file");
863 4 : *issued_error = true;
864 : }
865 :
866 43840691 : return p + adv;
867 : }
868 :
869 : // Pick up an identifier.
870 :
871 : Token
872 6995860 : Lex::gather_identifier()
873 : {
874 6995860 : const char* pstart = this->linebuf_ + this->lineoff_;
875 6995860 : const char* p = pstart;
876 6995860 : const char* pend = this->linebuf_ + this->linesize_;
877 6995860 : bool is_first = true;
878 6995860 : bool is_exported = false;
879 6995860 : bool has_non_ascii_char = false;
880 6995860 : std::string buf;
881 41946668 : while (p < pend)
882 : {
883 41946667 : unsigned char cc = *p;
884 41946667 : if (cc <= 0x7f)
885 : {
886 41946398 : if ((cc < 'A' || cc > 'Z')
887 41946398 : && (cc < 'a' || cc > 'z')
888 8809188 : && cc != '_'
889 8144381 : && (cc < '0' || cc > '9'))
890 : {
891 : // Check for an invalid character here, as we get better
892 : // error behaviour if we swallow them as part of the
893 : // identifier we are building.
894 6995863 : if ((cc >= ' ' && cc < 0x7f)
895 6995863 : || cc == '\t'
896 405378 : || cc == '\r'
897 405378 : || cc == '\n')
898 : break;
899 :
900 4 : this->lineoff_ = p - this->linebuf_;
901 4 : go_error_at(this->location(),
902 : "invalid character 0x%x in identifier",
903 : cc);
904 4 : if (!has_non_ascii_char)
905 : {
906 4 : buf.assign(pstart, p - pstart);
907 4 : has_non_ascii_char = true;
908 : }
909 4 : if (!Lex::is_invalid_identifier(buf))
910 4 : buf.append("$INVALID$");
911 : }
912 34950539 : ++p;
913 34950539 : if (is_first)
914 : {
915 6995759 : is_exported = cc >= 'A' && cc <= 'Z';
916 6995759 : is_first = false;
917 : }
918 34950539 : if (has_non_ascii_char)
919 776 : buf.push_back(cc);
920 : }
921 : else
922 : {
923 269 : unsigned int ci;
924 269 : bool issued_error;
925 269 : this->lineoff_ = p - this->linebuf_;
926 269 : const char* pnext = this->advance_one_utf8_char(p, &ci,
927 : &issued_error);
928 269 : bool is_invalid = false;
929 269 : if (!Lex::is_unicode_letter(ci) && !Lex::is_unicode_digit(ci))
930 : {
931 : // There is no valid place for a non-ASCII character
932 : // other than an identifier, so we get better error
933 : // handling behaviour if we swallow this character after
934 : // giving an error.
935 3 : if (!issued_error)
936 1 : go_error_at(this->location(),
937 : "invalid character 0x%x in identifier",
938 : ci);
939 : is_invalid = true;
940 : }
941 269 : if (is_first)
942 : {
943 101 : is_exported = Lex::is_unicode_uppercase(ci);
944 101 : is_first = false;
945 : }
946 269 : if (!has_non_ascii_char)
947 : {
948 268 : buf.assign(pstart, p - pstart);
949 268 : has_non_ascii_char = true;
950 : }
951 269 : if (is_invalid && !Lex::is_invalid_identifier(buf))
952 2 : buf.append("$INVALID$");
953 269 : buf.append(p, pnext - p);
954 269 : p = pnext;
955 : }
956 : }
957 6995860 : Location location = this->location();
958 6995860 : this->add_semi_at_eol_ = true;
959 6995860 : this->lineoff_ = p - this->linebuf_;
960 6995860 : if (has_non_ascii_char)
961 272 : return Token::make_identifier_token(buf, is_exported, location);
962 : else
963 : {
964 6995588 : Keyword code = keywords.keyword_to_code(pstart, p - pstart);
965 6995588 : if (code == KEYWORD_INVALID)
966 5885742 : return Token::make_identifier_token(std::string(pstart, p - pstart),
967 5885742 : is_exported, location);
968 : else
969 : {
970 1109846 : switch (code)
971 : {
972 : case KEYWORD_BREAK:
973 : case KEYWORD_CONTINUE:
974 : case KEYWORD_FALLTHROUGH:
975 : case KEYWORD_RETURN:
976 : break;
977 897575 : default:
978 897575 : this->add_semi_at_eol_ = false;
979 897575 : break;
980 : }
981 1109846 : return Token::make_keyword_token(code, location);
982 : }
983 : }
984 6995860 : }
985 :
986 : // Return whether C is a hex digit.
987 :
988 : bool
989 6126441 : Lex::is_hex_digit(char c)
990 : {
991 6126441 : return ((c >= '0' && c <= '9')
992 6126441 : || (c >= 'A' && c <= 'F')
993 6126441 : || (c >= 'a' && c <= 'f'));
994 : }
995 :
996 : // Return whether C is a valid digit in BASE.
997 :
998 : bool
999 3822778 : Lex::is_base_digit(int base, char c)
1000 : {
1001 3822778 : switch (base)
1002 : {
1003 774 : case 2:
1004 774 : return c == '0' || c == '1';
1005 0 : case 8:
1006 0 : return c >= '0' && c <= '7';
1007 548470 : case 10:
1008 548470 : return c >= '0' && c <= '9';
1009 3273534 : case 16:
1010 3273534 : return Lex::is_hex_digit(c);
1011 0 : default:
1012 0 : go_unreachable();
1013 : }
1014 : }
1015 :
1016 : // not a hex value
1017 : #define NHV 100
1018 :
1019 : // for use by Lex::hex_val
1020 : static const unsigned char hex_value_lookup_table[256] =
1021 : {
1022 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, // NUL SOH STX ETX EOT ENQ ACK BEL
1023 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, // BS HT LF VT FF CR SO SI
1024 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, // DLE DC1 DC2 DC3 DC4 NAK SYN ETB
1025 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, // CAN EM SUB ESC FS GS RS US
1026 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, // SP ! " # $ % & '
1027 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, // ( ) * + , - . /
1028 : 0, 1, 2, 3, 4, 5, 6, 7, // 0 1 2 3 4 5 6 7
1029 : 8, 9, NHV, NHV, NHV, NHV, NHV, NHV, // 8 9 : ; < = > ?
1030 : NHV, 10, 11, 12, 13, 14, 15, NHV, // @ A B C D E F G
1031 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, // H I J K L M N O
1032 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, // P Q R S T U V W
1033 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, // X Y Z [ \ ] ^ _
1034 : NHV, 10, 11, 12, 13, 14, 15, NHV, // ` a b c d e f g
1035 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, // h i j k l m n o
1036 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, // p q r s t u v w
1037 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, // x y z { | } ~
1038 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1039 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1040 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1041 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1042 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1043 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1044 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1045 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1046 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1047 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1048 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1049 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1050 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1051 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1052 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV, //
1053 : NHV, NHV, NHV, NHV, NHV, NHV, NHV, NHV //
1054 : };
1055 :
1056 : unsigned
1057 2852902 : Lex::hex_val(char c)
1058 : {
1059 2852902 : return hex_value_lookup_table[static_cast<unsigned char>(c)];
1060 : }
1061 :
1062 : // Return whether an exponent could start at P, in base BASE.
1063 :
1064 : bool
1065 1280981 : Lex::could_be_exponent(int base, const char* p, const char* pend)
1066 : {
1067 1280981 : switch (base)
1068 : {
1069 668620 : case 10:
1070 668620 : if (*p != 'e' && *p != 'E')
1071 : return false;
1072 : break;
1073 612361 : case 16:
1074 612361 : if (*p != 'p' && *p != 'P')
1075 : return false;
1076 : break;
1077 0 : default:
1078 0 : go_unreachable();
1079 : }
1080 10993 : ++p;
1081 10993 : if (p >= pend)
1082 : return false;
1083 10993 : if (*p == '+' || *p == '-')
1084 : {
1085 8114 : ++p;
1086 8114 : if (p >= pend)
1087 : return false;
1088 : }
1089 10993 : return *p >= '0' && *p <= '9';
1090 : }
1091 :
1092 : // Pick up a number.
1093 :
1094 : Token
1095 1281374 : Lex::gather_number()
1096 : {
1097 1281374 : const char* pstart = this->linebuf_ + this->lineoff_;
1098 1281374 : const char* p = pstart;
1099 1281374 : const char* pend = this->linebuf_ + this->linesize_;
1100 :
1101 1281374 : Location location = this->location();
1102 :
1103 1281374 : int base = 10;
1104 1281374 : std::string num;
1105 1281374 : if (*p == '0')
1106 : {
1107 775418 : int basecheck;
1108 775418 : int off;
1109 775418 : if (p[1] == 'x' || p[1] == 'X')
1110 : {
1111 : base = 16;
1112 : basecheck = 16;
1113 : off = 2;
1114 : }
1115 : else if (p[1] == 'o' || p[1] == 'O')
1116 : {
1117 : base = 8;
1118 : basecheck = 8;
1119 : off = 2;
1120 : }
1121 : else if (p[1] == 'b' || p[1] == 'B')
1122 : {
1123 : base = 2;
1124 : basecheck = 2;
1125 : off = 2;
1126 : }
1127 : else
1128 : {
1129 : // Old style octal literal. May also be the start of a
1130 : // floating-point number (e.g., 09.2, 09e2) or an imaginary
1131 : // literal (e.g., 09i), so we have to accept decimal digits.
1132 775418 : base = 8;
1133 775418 : basecheck = 10;
1134 775418 : off = 0;
1135 : }
1136 :
1137 775418 : p += off;
1138 775418 : if (*p == '_' && Lex::is_base_digit(basecheck, p[1]))
1139 0 : ++p;
1140 :
1141 3616107 : while (Lex::is_base_digit(basecheck, *p))
1142 : {
1143 2840689 : num.push_back(*p);
1144 2840689 : ++p;
1145 2840689 : if (*p == '_' && Lex::is_base_digit(basecheck, p[1]))
1146 0 : ++p;
1147 : }
1148 :
1149 : // We must see at least one valid digit, except for a case like
1150 : // 0x.0p1.
1151 775418 : if (num.length() == 0 && (base != 16 || *p != '.'))
1152 : {
1153 0 : go_error_at(this->location(), "invalid numeric literal");
1154 0 : this->lineoff_ = p - this->linebuf_;
1155 0 : mpz_t val;
1156 0 : mpz_init_set_ui(val, 0);
1157 0 : Token ret = Token::make_integer_token(val, location);
1158 0 : mpz_clear(val);
1159 0 : return ret;
1160 : }
1161 :
1162 775418 : bool is_float = false;
1163 : // A number that looks like an old-style octal literal might
1164 : // actually be the beginning of a floating-point or imaginary
1165 : // literal, in which case the value is decimal digits. Handle
1166 : // that case below by treating the leading '0' as decimal.
1167 775418 : if (off == 0
1168 775418 : && (*p == '.' || *p == 'i' || Lex::could_be_exponent(10, p, pend)))
1169 : {
1170 : is_float = true;
1171 : base = 10;
1172 : }
1173 770156 : else if (base == 16
1174 770156 : && (*p == '.' || Lex::could_be_exponent(16, p, pend)))
1175 : is_float = true;
1176 :
1177 770081 : if (!is_float)
1178 : {
1179 770081 : mpz_t val;
1180 770081 : int r = mpz_init_set_str(val, num.c_str(), base);
1181 770081 : if (r != 0)
1182 : {
1183 0 : const char *errword;
1184 0 : switch (base)
1185 : {
1186 : case 2:
1187 : errword = "binary";
1188 : break;
1189 0 : case 8:
1190 0 : errword = "octal";
1191 0 : break;
1192 0 : case 16:
1193 0 : errword = "hex";
1194 0 : break;
1195 0 : default:
1196 0 : go_unreachable();
1197 : }
1198 0 : go_error_at(this->location(), "invalid %s literal", errword);
1199 : }
1200 :
1201 770081 : bool is_imaginary = *p == 'i';
1202 770081 : if (is_imaginary)
1203 0 : ++p;
1204 :
1205 770081 : this->lineoff_ = p - this->linebuf_;
1206 :
1207 770081 : if (*p == 'e' || *p == 'E' || *p == 'p' || *p == 'P')
1208 : {
1209 1 : go_error_at(location,
1210 : "invalid prefix for floating constant");
1211 1 : this->skip_exponent();
1212 : }
1213 :
1214 770081 : if (!is_imaginary)
1215 : {
1216 770081 : Token ret = Token::make_integer_token(val, location);
1217 770081 : mpz_clear(val);
1218 770081 : return ret;
1219 770081 : }
1220 : else
1221 : {
1222 0 : mpfr_t ival;
1223 0 : mpfr_init_set_z(ival, val, MPFR_RNDN);
1224 0 : mpz_clear(val);
1225 0 : Token ret = Token::make_imaginary_token(ival, location);
1226 0 : mpfr_clear(ival);
1227 0 : return ret;
1228 0 : }
1229 : }
1230 : }
1231 :
1232 1479996 : while (p < pend)
1233 : {
1234 1479996 : if (*p == '_' && p[1] >= '0' && p[1] <= '9')
1235 58 : ++p;
1236 1479938 : else if (*p < '0' || *p > '9')
1237 : break;
1238 968703 : num.push_back(*p);
1239 968703 : ++p;
1240 : }
1241 :
1242 511293 : if (*p != '.' && *p != 'i' && !Lex::could_be_exponent(base, p, pend))
1243 : {
1244 491586 : mpz_t val;
1245 491586 : int r = mpz_init_set_str(val, num.c_str(), 10);
1246 491586 : go_assert(r == 0);
1247 :
1248 491586 : this->lineoff_ = p - this->linebuf_;
1249 :
1250 491586 : if (*p == 'e' || *p == 'E' || *p == 'p' || *p == 'P')
1251 : {
1252 1 : go_error_at(location,
1253 : "invalid prefix for floating constant");
1254 1 : this->skip_exponent();
1255 : }
1256 :
1257 491586 : Token ret = Token::make_integer_token(val, location);
1258 491586 : mpz_clear(val);
1259 491586 : return ret;
1260 491586 : }
1261 :
1262 19707 : if (*p != 'i')
1263 : {
1264 19276 : bool dot = *p == '.';
1265 :
1266 19276 : num.push_back(*p);
1267 19276 : ++p;
1268 :
1269 19276 : if (!dot)
1270 : {
1271 2756 : if (*p == '+' || *p == '-')
1272 : {
1273 461 : num.push_back(*p);
1274 461 : ++p;
1275 : }
1276 : }
1277 :
1278 : bool first = true;
1279 206671 : while (p < pend)
1280 : {
1281 206671 : if (!first && *p == '_' && Lex::is_base_digit(base, p[1]))
1282 0 : ++p;
1283 206671 : else if (!Lex::is_base_digit(base, *p))
1284 : break;
1285 187395 : num.push_back(*p);
1286 187395 : ++p;
1287 187395 : first = false;
1288 : }
1289 :
1290 19276 : if (dot && Lex::could_be_exponent(base, p, pend))
1291 : {
1292 8101 : num.push_back(*p);
1293 8101 : ++p;
1294 8101 : if (*p == '+' || *p == '-')
1295 : {
1296 7612 : num.push_back(*p);
1297 7612 : ++p;
1298 : }
1299 : first = true;
1300 24426 : while (p < pend)
1301 : {
1302 24426 : if (!first && *p == '_' && p[1] >= '0' && p[1] <= '9')
1303 0 : ++p;
1304 24426 : else if (*p < '0' || *p > '9')
1305 : break;
1306 16325 : num.push_back(*p);
1307 16325 : ++p;
1308 16325 : first = false;
1309 : }
1310 : }
1311 11175 : else if (dot && base == 16)
1312 : {
1313 0 : go_error_at(this->location(),
1314 : "invalid hex floating-point literal with no exponent");
1315 0 : num.append("p0");
1316 : }
1317 : }
1318 :
1319 19707 : mpfr_clear_overflow();
1320 19707 : mpfr_t val;
1321 19707 : int r = mpfr_init_set_str(val, num.c_str(), base, MPFR_RNDN);
1322 19707 : go_assert(r == 0);
1323 19707 : if (mpfr_overflow_p())
1324 11 : go_error_at(this->location(),
1325 : "floating-point exponent too large to represent");
1326 :
1327 19707 : bool is_imaginary = *p == 'i';
1328 19707 : if (is_imaginary)
1329 993 : ++p;
1330 :
1331 19707 : this->lineoff_ = p - this->linebuf_;
1332 :
1333 19707 : if (*p == 'e' || *p == 'E' || *p == 'p' || *p == 'P')
1334 : {
1335 0 : go_error_at(location,
1336 : "invalid prefix for floating constant");
1337 0 : this->skip_exponent();
1338 : }
1339 :
1340 19707 : if (is_imaginary)
1341 : {
1342 993 : Token ret = Token::make_imaginary_token(val, location);
1343 993 : mpfr_clear(val);
1344 993 : return ret;
1345 993 : }
1346 : else
1347 : {
1348 18714 : Token ret = Token::make_float_token(val, location);
1349 18714 : mpfr_clear(val);
1350 18714 : return ret;
1351 18714 : }
1352 1281374 : }
1353 :
1354 : // Skip an exponent after reporting an error.
1355 :
1356 : void
1357 2 : Lex::skip_exponent()
1358 : {
1359 2 : const char* p = this->linebuf_ + this->lineoff_;
1360 2 : const char* pend = this->linebuf_ + this->linesize_;
1361 2 : if (*p != 'e' && *p != 'E' && *p != 'p' && *p != 'P')
1362 : return;
1363 2 : ++p;
1364 2 : if (*p == '+' || *p == '-')
1365 0 : ++p;
1366 5 : while (p < pend)
1367 : {
1368 5 : if ((*p < '0' || *p > '9') && *p != '_')
1369 : break;
1370 3 : ++p;
1371 : }
1372 2 : this->lineoff_ = p - this->linebuf_;
1373 : }
1374 :
1375 : // Advance one character, possibly escaped. Return the pointer beyond
1376 : // the character. Set *VALUE to the character. Set *IS_CHARACTER if
1377 : // this is a character (e.g., 'a' or '\u1234') rather than a byte
1378 : // value (e.g., '\001').
1379 :
1380 : const char*
1381 7765791 : Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
1382 : bool* is_character)
1383 : {
1384 7765791 : *value = 0;
1385 7765791 : *is_character = true;
1386 7765791 : if (*p != '\\')
1387 : {
1388 6300449 : bool issued_error;
1389 6300449 : const char* ret = this->advance_one_utf8_char(p, value, &issued_error);
1390 6300449 : if (is_single_quote
1391 29759 : && (*value == '\'' || *value == '\n')
1392 1 : && !issued_error)
1393 1 : go_error_at(this->location(), "invalid character literal");
1394 6300449 : return ret;
1395 : }
1396 : else
1397 : {
1398 1465342 : ++p;
1399 1465342 : switch (*p)
1400 : {
1401 124 : case '0': case '1': case '2': case '3':
1402 124 : case '4': case '5': case '6': case '7':
1403 124 : *is_character = false;
1404 124 : if (p[1] >= '0' && p[1] <= '7'
1405 123 : && p[2] >= '0' && p[2] <= '7')
1406 : {
1407 122 : *value = ((Lex::octal_value(p[0]) << 6)
1408 122 : + (Lex::octal_value(p[1]) << 3)
1409 122 : + Lex::octal_value(p[2]));
1410 122 : if (*value > 255)
1411 : {
1412 0 : go_error_at(this->location(), "invalid octal constant");
1413 0 : *value = 255;
1414 : }
1415 122 : return p + 3;
1416 : }
1417 2 : go_error_at(this->location(), "invalid octal character");
1418 2 : return (p[1] >= '0' && p[1] <= '7'
1419 2 : ? p + 2
1420 2 : : p + 1);
1421 :
1422 1360367 : case 'x':
1423 1360367 : *is_character = false;
1424 1360367 : if (Lex::is_hex_digit(p[1]) && Lex::is_hex_digit(p[2]))
1425 : {
1426 1360365 : *value = (Lex::hex_val(p[1]) << 4) + Lex::hex_val(p[2]);
1427 1360365 : return p + 3;
1428 : }
1429 2 : go_error_at(this->location(), "invalid hex character");
1430 2 : return (Lex::is_hex_digit(p[1])
1431 2 : ? p + 2
1432 2 : : p + 1);
1433 :
1434 4887 : case 'a':
1435 4887 : *value = '\a';
1436 4887 : return p + 1;
1437 5989 : case 'b':
1438 5989 : *value = '\b';
1439 5989 : return p + 1;
1440 4643 : case 'f':
1441 4643 : *value = '\f';
1442 4643 : return p + 1;
1443 36225 : case 'n':
1444 36225 : *value = '\n';
1445 36225 : return p + 1;
1446 6905 : case 'r':
1447 6905 : *value = '\r';
1448 6905 : return p + 1;
1449 11147 : case 't':
1450 11147 : *value = '\t';
1451 11147 : return p + 1;
1452 7497 : case 'v':
1453 7497 : *value = '\v';
1454 7497 : return p + 1;
1455 2459 : case '\\':
1456 2459 : *value = '\\';
1457 2459 : return p + 1;
1458 469 : case '\'':
1459 469 : if (!is_single_quote)
1460 1 : go_error_at(this->location(), "invalid quoted character");
1461 469 : *value = '\'';
1462 469 : return p + 1;
1463 4558 : case '"':
1464 4558 : if (is_single_quote)
1465 0 : go_error_at(this->location(), "invalid quoted character");
1466 4558 : *value = '"';
1467 4558 : return p + 1;
1468 :
1469 7101 : case 'u':
1470 14202 : if (Lex::is_hex_digit(p[1]) && Lex::is_hex_digit(p[2])
1471 14202 : && Lex::is_hex_digit(p[3]) && Lex::is_hex_digit(p[4]))
1472 : {
1473 7101 : *value = ((Lex::hex_val(p[1]) << 12)
1474 7101 : + (Lex::hex_val(p[2]) << 8)
1475 7101 : + (Lex::hex_val(p[3]) << 4)
1476 7101 : + Lex::hex_val(p[4]));
1477 7101 : if (*value >= 0xd800 && *value < 0xe000)
1478 : {
1479 3 : go_error_at(this->location(),
1480 : "invalid unicode code point 0x%x",
1481 : *value);
1482 : // Use the replacement character.
1483 3 : *value = 0xfffd;
1484 : }
1485 7101 : return p + 5;
1486 : }
1487 0 : go_error_at(this->location(), "invalid little unicode code point");
1488 0 : return p + 1;
1489 :
1490 12971 : case 'U':
1491 25942 : if (Lex::is_hex_digit(p[1]) && Lex::is_hex_digit(p[2])
1492 12971 : && Lex::is_hex_digit(p[3]) && Lex::is_hex_digit(p[4])
1493 12971 : && Lex::is_hex_digit(p[5]) && Lex::is_hex_digit(p[6])
1494 25942 : && Lex::is_hex_digit(p[7]) && Lex::is_hex_digit(p[8]))
1495 : {
1496 12971 : *value = ((Lex::hex_val(p[1]) << 28)
1497 12971 : + (Lex::hex_val(p[2]) << 24)
1498 12971 : + (Lex::hex_val(p[3]) << 20)
1499 12971 : + (Lex::hex_val(p[4]) << 16)
1500 12971 : + (Lex::hex_val(p[5]) << 12)
1501 12971 : + (Lex::hex_val(p[6]) << 8)
1502 12971 : + (Lex::hex_val(p[7]) << 4)
1503 12971 : + Lex::hex_val(p[8]));
1504 12971 : if (*value > 0x10ffff
1505 12971 : || (*value >= 0xd800 && *value < 0xe000))
1506 : {
1507 5 : go_error_at(this->location(),
1508 : "invalid unicode code point 0x%x",
1509 : *value);
1510 : // Use the replacement character.
1511 5 : *value = 0xfffd;
1512 : }
1513 12971 : return p + 9;
1514 : }
1515 0 : go_error_at(this->location(), "invalid big unicode code point");
1516 0 : return p + 1;
1517 :
1518 0 : default:
1519 0 : go_error_at(this->location(), "invalid character after %<\\%>");
1520 0 : *value = *p;
1521 0 : return p + 1;
1522 : }
1523 : }
1524 : }
1525 :
1526 : // Append V to STR. IS_CHARACTER is true for a character which should
1527 : // be stored in UTF-8, false for a general byte value which should be
1528 : // stored directly.
1529 :
1530 : void
1531 10305708 : Lex::append_char(unsigned int v, bool is_character, std::string* str,
1532 : Location location)
1533 : {
1534 10305708 : char buf[4];
1535 10305708 : size_t len;
1536 10305708 : if (v <= 0x7f || !is_character)
1537 : {
1538 9273491 : buf[0] = v;
1539 9273491 : len = 1;
1540 : }
1541 1032217 : else if (v <= 0x7ff)
1542 : {
1543 20247 : buf[0] = 0xc0 + (v >> 6);
1544 20247 : buf[1] = 0x80 + (v & 0x3f);
1545 20247 : len = 2;
1546 : }
1547 : else
1548 : {
1549 1011970 : if (v > 0x10ffff)
1550 : {
1551 9 : go_warning_at(location, 0,
1552 : "unicode code point 0x%x out of range in string", v);
1553 : // Turn it into the "replacement character".
1554 9 : v = 0xfffd;
1555 : }
1556 1011970 : if (v >= 0xd800 && v < 0xe000)
1557 : {
1558 2 : go_warning_at(location, 0,
1559 : "unicode code point 0x%x is invalid surrogate pair", v);
1560 2 : v = 0xfffd;
1561 : }
1562 1011970 : if (v <= 0xffff)
1563 : {
1564 1011384 : buf[0] = 0xe0 + (v >> 12);
1565 1011384 : buf[1] = 0x80 + ((v >> 6) & 0x3f);
1566 1011384 : buf[2] = 0x80 + (v & 0x3f);
1567 1011384 : len = 3;
1568 : }
1569 : else
1570 : {
1571 586 : buf[0] = 0xf0 + (v >> 18);
1572 586 : buf[1] = 0x80 + ((v >> 12) & 0x3f);
1573 586 : buf[2] = 0x80 + ((v >> 6) & 0x3f);
1574 586 : buf[3] = 0x80 + (v & 0x3f);
1575 586 : len = 4;
1576 : }
1577 : }
1578 10305708 : str->append(buf, len);
1579 10305708 : }
1580 :
1581 : // Pick up a character literal.
1582 :
1583 : Token
1584 49036 : Lex::gather_character()
1585 : {
1586 49036 : ++this->lineoff_;
1587 49036 : const char* pstart = this->linebuf_ + this->lineoff_;
1588 49036 : const char* p = pstart;
1589 :
1590 49036 : unsigned int value;
1591 49036 : bool is_character;
1592 49036 : p = this->advance_one_char(p, true, &value, &is_character);
1593 :
1594 49036 : if (*p != '\'')
1595 : {
1596 0 : go_error_at(this->location(), "unterminated character constant");
1597 0 : this->lineoff_ = p - this->linebuf_;
1598 0 : return this->make_invalid_token();
1599 : }
1600 :
1601 49036 : mpz_t val;
1602 49036 : mpz_init_set_ui(val, value);
1603 :
1604 49036 : Location location = this->location();
1605 49036 : this->lineoff_ = p + 1 - this->linebuf_;
1606 49036 : Token ret = Token::make_character_token(val, location);
1607 49036 : mpz_clear(val);
1608 49036 : return ret;
1609 49036 : }
1610 :
1611 : // Pick up a quoted string.
1612 :
1613 : Token
1614 432554 : Lex::gather_string()
1615 : {
1616 432554 : const char* pstart = this->linebuf_ + this->lineoff_ + 1;
1617 432554 : const char* p = pstart;
1618 432554 : const char* pend = this->linebuf_ + this->linesize_;
1619 :
1620 432554 : std::string value;
1621 8149219 : while (*p != '"')
1622 : {
1623 7716665 : Location loc = this->location();
1624 7716665 : unsigned int c;
1625 7716665 : bool is_character;
1626 7716665 : this->lineoff_ = p - this->linebuf_;
1627 7716665 : p = this->advance_one_char(p, false, &c, &is_character);
1628 7716665 : if (p >= pend)
1629 : {
1630 0 : go_error_at(this->location(), "unterminated string");
1631 0 : --p;
1632 0 : break;
1633 : }
1634 7716665 : Lex::append_char(c, is_character, &value, loc);
1635 : }
1636 :
1637 432554 : Location location = this->location();
1638 432554 : this->lineoff_ = p + 1 - this->linebuf_;
1639 432554 : return Token::make_string_token(value, location);
1640 432554 : }
1641 :
1642 : // Pick up a raw string.
1643 :
1644 : Token
1645 27941 : Lex::gather_raw_string()
1646 : {
1647 27941 : const char* p = this->linebuf_ + this->lineoff_ + 1;
1648 27941 : const char* pend = this->linebuf_ + this->linesize_;
1649 27941 : Location location = this->location();
1650 :
1651 27941 : std::string value;
1652 50958 : while (true)
1653 : {
1654 2667358 : while (p < pend)
1655 : {
1656 2616400 : if (*p == '`')
1657 : {
1658 27941 : this->lineoff_ = p + 1 - this->linebuf_;
1659 27941 : return Token::make_string_token(value, location);
1660 : }
1661 2588459 : Location loc = this->location();
1662 2588459 : unsigned int c;
1663 2588459 : bool issued_error;
1664 2588459 : this->lineoff_ = p - this->linebuf_;
1665 2588459 : p = this->advance_one_utf8_char(p, &c, &issued_error);
1666 : // "Carriage return characters ('\r') inside raw string literals
1667 : // are discarded from the raw string value."
1668 2588459 : if (c != '\r')
1669 2588451 : Lex::append_char(c, true, &value, loc);
1670 : }
1671 50958 : this->lineoff_ = p - this->linebuf_;
1672 50958 : if (!this->require_line())
1673 : {
1674 0 : go_error_at(location, "unterminated raw string");
1675 0 : return Token::make_string_token(value, location);
1676 : }
1677 50958 : p = this->linebuf_ + this->lineoff_;
1678 50958 : pend = this->linebuf_ + this->linesize_;
1679 50958 : }
1680 27941 : }
1681 :
1682 : // If C1 C2 C3 are a three character operator, return the code.
1683 :
1684 : Operator
1685 238018 : Lex::three_character_operator(char c1, char c2, char c3)
1686 : {
1687 238018 : if (c3 == '=')
1688 : {
1689 2273 : if (c1 == '<' && c2 == '<')
1690 : return OPERATOR_LSHIFTEQ;
1691 1680 : else if (c1 == '>' && c2 == '>')
1692 : return OPERATOR_RSHIFTEQ;
1693 545 : else if (c1 == '&' && c2 == '^')
1694 545 : return OPERATOR_BITCLEAREQ;
1695 : }
1696 : return OPERATOR_INVALID;
1697 : }
1698 :
1699 : // If C1 C2 are a two character operator, return the code.
1700 :
1701 : Operator
1702 8190527 : Lex::two_character_operator(char c1, char c2)
1703 : {
1704 8190527 : switch (c1)
1705 : {
1706 40458 : case '|':
1707 40458 : if (c2 == '|')
1708 : return OPERATOR_OROR;
1709 13840 : else if (c2 == '=')
1710 2764 : return OPERATOR_OREQ;
1711 : break;
1712 113862 : case '&':
1713 113862 : if (c2 == '&')
1714 : return OPERATOR_ANDAND;
1715 76404 : else if (c2 == '^')
1716 : return OPERATOR_BITCLEAR;
1717 74965 : else if (c2 == '=')
1718 584 : return OPERATOR_ANDEQ;
1719 : break;
1720 6387 : case '^':
1721 6387 : if (c2 == '=')
1722 824 : return OPERATOR_XOREQ;
1723 : break;
1724 474703 : case '=':
1725 474703 : if (c2 == '=')
1726 88337 : return OPERATOR_EQEQ;
1727 : break;
1728 151122 : case '!':
1729 151122 : if (c2 == '=')
1730 118937 : return OPERATOR_NOTEQ;
1731 : break;
1732 78368 : case '<':
1733 78368 : if (c2 == '=')
1734 : return OPERATOR_LE;
1735 68262 : else if (c2 == '<')
1736 : return OPERATOR_LSHIFT;
1737 46813 : else if (c2 == '-')
1738 11971 : return OPERATOR_CHANOP;
1739 : break;
1740 43515 : case '>':
1741 43515 : if (c2 == '=')
1742 : return OPERATOR_GE;
1743 33620 : else if (c2 == '>')
1744 12004 : return OPERATOR_RSHIFT;
1745 : break;
1746 193896 : case '*':
1747 193896 : if (c2 == '=')
1748 924 : return OPERATOR_MULTEQ;
1749 : break;
1750 0 : case '/':
1751 0 : if (c2 == '=')
1752 0 : return OPERATOR_DIVEQ;
1753 : break;
1754 4319 : case '%':
1755 4319 : if (c2 == '=')
1756 54 : return OPERATOR_MODEQ;
1757 : break;
1758 140939 : case '+':
1759 140939 : if (c2 == '+')
1760 : {
1761 23183 : this->add_semi_at_eol_ = true;
1762 23183 : return OPERATOR_PLUSPLUS;
1763 : }
1764 117756 : else if (c2 == '=')
1765 13607 : return OPERATOR_PLUSEQ;
1766 : break;
1767 101265 : case '-':
1768 101265 : if (c2 == '-')
1769 : {
1770 4271 : this->add_semi_at_eol_ = true;
1771 4271 : return OPERATOR_MINUSMINUS;
1772 : }
1773 96994 : else if (c2 == '=')
1774 3872 : return OPERATOR_MINUSEQ;
1775 : break;
1776 635822 : case ':':
1777 635822 : if (c2 == '=')
1778 257431 : return OPERATOR_COLONEQ;
1779 : break;
1780 : default:
1781 : break;
1782 : }
1783 : return OPERATOR_INVALID;
1784 : }
1785 :
1786 : // If character C is an operator, return the code.
1787 :
1788 : Operator
1789 7544799 : Lex::one_character_operator(char c)
1790 : {
1791 7544799 : switch (c)
1792 : {
1793 : case '<':
1794 : return OPERATOR_LT;
1795 21616 : case '>':
1796 21616 : return OPERATOR_GT;
1797 104149 : case '+':
1798 104149 : return OPERATOR_PLUS;
1799 93122 : case '-':
1800 93122 : return OPERATOR_MINUS;
1801 11076 : case '|':
1802 11076 : return OPERATOR_OR;
1803 5563 : case '^':
1804 5563 : return OPERATOR_XOR;
1805 192972 : case '*':
1806 192972 : return OPERATOR_MULT;
1807 0 : case '/':
1808 0 : return OPERATOR_DIV;
1809 4265 : case '%':
1810 4265 : return OPERATOR_MOD;
1811 74381 : case '&':
1812 74381 : return OPERATOR_AND;
1813 32185 : case '!':
1814 32185 : return OPERATOR_NOT;
1815 386366 : case '=':
1816 386366 : return OPERATOR_EQ;
1817 378391 : case ':':
1818 378391 : return OPERATOR_COLON;
1819 108898 : case ';':
1820 108898 : return OPERATOR_SEMICOLON;
1821 0 : case '.':
1822 0 : return OPERATOR_DOT;
1823 1709928 : case ',':
1824 1709928 : return OPERATOR_COMMA;
1825 1175627 : case '(':
1826 1175627 : return OPERATOR_LPAREN;
1827 1175625 : case ')':
1828 1175625 : this->add_semi_at_eol_ = true;
1829 1175625 : return OPERATOR_RPAREN;
1830 744485 : case '{':
1831 744485 : return OPERATOR_LCURLY;
1832 744472 : case '}':
1833 744472 : this->add_semi_at_eol_ = true;
1834 744472 : return OPERATOR_RCURLY;
1835 273418 : case '[':
1836 273418 : return OPERATOR_LSQUARE;
1837 273418 : case ']':
1838 273418 : this->add_semi_at_eol_ = true;
1839 273418 : return OPERATOR_RSQUARE;
1840 0 : default:
1841 0 : return OPERATOR_INVALID;
1842 : }
1843 : }
1844 :
1845 : // Skip a C-style comment.
1846 :
1847 : bool
1848 9291 : Lex::skip_c_comment(bool* found_newline)
1849 : {
1850 67823 : while (true)
1851 : {
1852 38557 : if (!this->require_line())
1853 : {
1854 0 : go_error_at(this->location(), "unterminated comment");
1855 0 : return false;
1856 : }
1857 :
1858 38557 : const char* p = this->linebuf_ + this->lineoff_;
1859 38557 : const char* pend = this->linebuf_ + this->linesize_;
1860 :
1861 1337242 : while (p < pend)
1862 : {
1863 1307976 : if (p[0] == '*' && p + 1 < pend && p[1] == '/')
1864 : {
1865 9291 : this->lineoff_ = p + 2 - this->linebuf_;
1866 9291 : return true;
1867 : }
1868 :
1869 1298685 : if (p[0] == '\n')
1870 29266 : *found_newline = true;
1871 :
1872 1298685 : this->lineoff_ = p - this->linebuf_;
1873 1298685 : unsigned int c;
1874 1298685 : bool issued_error;
1875 1298685 : p = this->advance_one_utf8_char(p, &c, &issued_error);
1876 : }
1877 :
1878 29266 : this->lineoff_ = p - this->linebuf_;
1879 29266 : }
1880 : }
1881 :
1882 : // Skip a C++-style comment.
1883 :
1884 : void
1885 731023 : Lex::skip_cpp_comment()
1886 : {
1887 : // Ensure that if EXTERN_ is set, it means that we just saw a
1888 : // //extern comment.
1889 731023 : this->extern_.clear();
1890 :
1891 731023 : Location loc = this->location();
1892 731023 : size_t lineoff = this->lineoff_;
1893 :
1894 731023 : const char* p = this->linebuf_ + lineoff;
1895 731023 : const char* pend = this->linebuf_ + this->linesize_;
1896 :
1897 731023 : const char* pcheck = p;
1898 731023 : bool saw_error = false;
1899 34379817 : while (pcheck < pend)
1900 : {
1901 33648794 : this->lineoff_ = pcheck - this->linebuf_;
1902 33648794 : unsigned int c;
1903 33648794 : bool issued_error;
1904 33648794 : pcheck = this->advance_one_utf8_char(pcheck, &c, &issued_error);
1905 33648794 : if (issued_error)
1906 4 : saw_error = true;
1907 : }
1908 :
1909 731023 : if (saw_error)
1910 720738 : return;
1911 :
1912 : // Recognize various magic comments at the start of a line, preceded
1913 : // only by spaces or tabs.
1914 :
1915 : // "- 2" for the "//" at the start of the comment.
1916 1309736 : for (const char* psp = this->linebuf_; psp < p - 2; psp++)
1917 654436 : if (*psp != ' ' && *psp != '\t')
1918 : return;
1919 :
1920 : while (pend > p
1921 1310606 : && (pend[-1] == ' ' || pend[-1] == '\t'
1922 : || pend[-1] == '\r' || pend[-1] == '\n'))
1923 655306 : --pend;
1924 :
1925 : // A C++ comment at the start of the line of the form
1926 : // //line FILE:LINENO
1927 : // is interpreted as setting the file name and line number of the
1928 : // next source line.
1929 655300 : if (pend - p > 5 && memcmp(p, "line ", 5) == 0)
1930 : {
1931 154 : p += 5;
1932 154 : while (p < pend && *p == ' ')
1933 0 : ++p;
1934 154 : const char* pcolon = static_cast<const char*>(memchr(p, ':', pend - p));
1935 154 : if (pcolon != NULL
1936 154 : && pcolon[1] >= '0'
1937 154 : && pcolon[1] <= '9')
1938 : {
1939 142 : char* plend;
1940 142 : long lineno = strtol(pcolon + 1, &plend, 10);
1941 142 : if (plend > pcolon + 1
1942 142 : && (plend == pend
1943 67 : || *plend < '0'
1944 67 : || *plend > '9')
1945 : && lineno > 0
1946 142 : && lineno < 0x7fffffff)
1947 : {
1948 142 : unsigned int filelen = pcolon - p;
1949 142 : char* file = new char[filelen + 1];
1950 142 : memcpy(file, p, filelen);
1951 142 : file[filelen] = '\0';
1952 :
1953 142 : this->linemap_->start_file(file, lineno);
1954 142 : this->lineno_ = lineno - 1;
1955 :
1956 142 : p = plend;
1957 : }
1958 : }
1959 154 : return;
1960 : }
1961 :
1962 : // As a special gccgo extension, a C++ comment at the start of the
1963 : // line of the form
1964 : // //extern NAME
1965 : // which immediately precedes a function declaration means that the
1966 : // external name of the function declaration is NAME. This is
1967 : // normally used to permit Go code to call a C function.
1968 655146 : if (pend - p > 7 && memcmp(p, "extern ", 7) == 0)
1969 : {
1970 613 : p += 7;
1971 613 : while (p < pend && (*p == ' ' || *p == '\t'))
1972 0 : ++p;
1973 613 : if (pend > p)
1974 613 : this->extern_ = std::string(p, pend - p);
1975 613 : return;
1976 : }
1977 :
1978 : // All other special comments start with "go:".
1979 :
1980 654533 : if (pend - p < 4 || memcmp(p, "go:", 3) != 0)
1981 : return;
1982 :
1983 10285 : const char *ps = p + 3;
1984 93997 : while (ps < pend && *ps != ' ' && *ps != '\t')
1985 83712 : ++ps;
1986 10285 : std::string verb = std::string(p, ps - p);
1987 :
1988 10285 : if (verb == "go:linkname")
1989 : {
1990 : // As in the gc compiler, set the external link name for a Go symbol.
1991 3920 : std::string go_name;
1992 3920 : std::string ext_name;
1993 3920 : bool is_exported = false;
1994 3920 : if (ps < pend)
1995 : {
1996 7840 : while (ps < pend && (*ps == ' ' || *ps == '\t'))
1997 3920 : ++ps;
1998 3920 : if (ps < pend)
1999 : {
2000 3920 : const char* pg = ps;
2001 :
2002 3920 : unsigned int c;
2003 3920 : bool issued_error;
2004 3920 : ps = this->advance_one_utf8_char(ps, &c, &issued_error);
2005 3920 : is_exported = Lex::is_unicode_uppercase(c);
2006 :
2007 54613 : while (ps < pend && *ps != ' ' && *ps != '\t')
2008 46773 : ++ps;
2009 3920 : if (ps <= pend)
2010 3920 : go_name = std::string(pg, ps - pg);
2011 6160 : while (ps < pend && (*ps == ' ' || *ps == '\t'))
2012 2240 : ++ps;
2013 : }
2014 3920 : if (ps < pend)
2015 : {
2016 : const char* pc = ps;
2017 37607 : while (ps < pend && *ps != ' ' && *ps != '\t')
2018 35367 : ++ps;
2019 2240 : if (ps <= pend)
2020 2240 : ext_name = std::string(pc, ps - pc);
2021 : }
2022 3920 : if (ps != pend)
2023 : {
2024 0 : go_name.clear();
2025 0 : ext_name.clear();
2026 : }
2027 : }
2028 3920 : if (go_name.empty())
2029 0 : go_error_at(loc, "usage: %<//go:linkname%> localname [linkname]");
2030 : else
2031 : {
2032 3920 : if (this->linknames_ == NULL)
2033 538 : this->linknames_ = new Linknames();
2034 7840 : (*this->linknames_)[go_name] = Linkname(ext_name, is_exported, loc);
2035 : }
2036 3920 : }
2037 6365 : else if (verb == "go:embed")
2038 23 : this->gather_embed(ps, pend);
2039 6342 : else if (verb == "go:nointerface")
2040 : {
2041 : // For field tracking analysis: a //go:nointerface comment means
2042 : // that the next interface method should not be stored in the
2043 : // type descriptor. This permits it to be discarded if it is
2044 : // not needed.
2045 1 : this->pragmas_ |= GOPRAGMA_NOINTERFACE;
2046 : }
2047 6341 : else if (verb == "go:noescape")
2048 : {
2049 : // Applies to the next function declaration. Any arguments do
2050 : // not escape.
2051 : // FIXME: Not implemented.
2052 1608 : this->pragmas_ |= GOPRAGMA_NOESCAPE;
2053 : }
2054 4733 : else if (verb == "go:nosplit")
2055 : {
2056 : // Applies to the next function. Do not split the stack when
2057 : // entering the function.
2058 1434 : this->pragmas_ |= GOPRAGMA_NOSPLIT;
2059 : }
2060 3299 : else if (verb == "go:noinline")
2061 : {
2062 : // Applies to the next function. Do not inline the function.
2063 360 : this->pragmas_ |= GOPRAGMA_NOINLINE;
2064 : }
2065 2939 : else if (verb == "go:notinheap")
2066 : {
2067 : // Applies to the next type. The type does not live in the heap.
2068 203 : this->pragmas_ |= GOPRAGMA_NOTINHEAP;
2069 : }
2070 2736 : else if (verb == "go:systemstack")
2071 : {
2072 : // Applies to the next function. It must run on the system stack.
2073 : // FIXME: Should only work when compiling the runtime package.
2074 : // FIXME: Not implemented.
2075 203 : this->pragmas_ |= GOPRAGMA_SYSTEMSTACK;
2076 : }
2077 2533 : else if (verb == "go:nowritebarrier")
2078 : {
2079 : // Applies to the next function. If the function needs to use
2080 : // any write barriers, it should emit an error instead.
2081 : // FIXME: Should only work when compiling the runtime package.
2082 301 : this->pragmas_ |= GOPRAGMA_NOWRITEBARRIER;
2083 : }
2084 2232 : else if (verb == "go:nowritebarrierrec")
2085 : {
2086 : // Applies to the next function. If the function, or any
2087 : // function that it calls, needs to use any write barriers, it
2088 : // should emit an error instead.
2089 : // FIXME: Should only work when compiling the runtime package.
2090 451 : this->pragmas_ |= GOPRAGMA_NOWRITEBARRIERREC;
2091 : }
2092 1781 : else if (verb == "go:yeswritebarrierrec")
2093 : {
2094 : // Applies to the next function. Disables go:nowritebarrierrec
2095 : // when looking at callees; write barriers are permitted here.
2096 : // FIXME: Should only work when compiling the runtime package.
2097 42 : this->pragmas_ |= GOPRAGMA_YESWRITEBARRIERREC;
2098 : }
2099 1739 : else if (verb == "go:cgo_unsafe_args")
2100 : {
2101 : // Applies to the next function. Taking the address of any
2102 : // argument implies taking the address of all arguments.
2103 : // FIXME: Not implemented.
2104 0 : this->pragmas_ |= GOPRAGMA_CGOUNSAFEARGS;
2105 : }
2106 1739 : else if (verb == "go:uintptrescapes")
2107 : {
2108 : // Applies to the next function. If an argument is a pointer
2109 : // converted to uintptr, then the pointer escapes.
2110 : // FIXME: Not implemented.
2111 12 : this->pragmas_ |= GOPRAGMA_UINTPTRESCAPES;
2112 : }
2113 10285 : }
2114 :
2115 : // Read a go:embed directive. This is a series of space-separated
2116 : // patterns. Each pattern may be a quoted or backquoted string.
2117 :
2118 : void
2119 23 : Lex::gather_embed(const char *p, const char *pend)
2120 : {
2121 47 : while (true)
2122 : {
2123 : // Skip spaces to find the start of the next pattern. We do a
2124 : // fast skip of space and tab, but we also permit and skip
2125 : // Unicode space characters.
2126 71 : while (p < pend && (*p == ' ' || *p == '\t'))
2127 24 : ++p;
2128 47 : if (p >= pend)
2129 : break;
2130 24 : unsigned int c;
2131 24 : bool issued_error;
2132 24 : const char *pnext = this->advance_one_utf8_char(p, &c, &issued_error);
2133 24 : if (issued_error)
2134 0 : return;
2135 24 : if (Lex::is_unicode_space(c))
2136 : {
2137 0 : p = pnext;
2138 0 : continue;
2139 : }
2140 :
2141 : // Here P points to the start of the next pattern, PNEXT points
2142 : // to the second character in the pattern, and C is the first
2143 : // character in that pattern (the character to which P points).
2144 :
2145 24 : if (c == '"' || c == '`')
2146 : {
2147 5 : Location loc = this->location();
2148 5 : const unsigned char quote = c;
2149 5 : std::string value;
2150 5 : p = pnext;
2151 95 : while (p < pend && *p != quote)
2152 : {
2153 90 : bool is_character;
2154 90 : if (quote == '"')
2155 90 : p = this->advance_one_char(p, false, &c, &is_character);
2156 : else
2157 : {
2158 0 : p = this->advance_one_utf8_char(p, &c, &issued_error);
2159 0 : if (issued_error)
2160 0 : return;
2161 : // "Carriage return characters ('\r') inside raw string
2162 : // literals are discarded from the raw string value."
2163 0 : if (c == '\r')
2164 0 : continue;
2165 0 : is_character = true;
2166 : }
2167 90 : Lex::append_char(c, is_character, &value, loc);
2168 : }
2169 5 : if (p >= pend)
2170 : {
2171 : // Note that within a go:embed directive we do not
2172 : // permit raw strings to cross multiple lines.
2173 0 : go_error_at(loc, "unterminated string");
2174 0 : return;
2175 : }
2176 5 : this->embeds_.push_back(value);
2177 5 : ++p;
2178 5 : }
2179 : else
2180 : {
2181 : const char *start = p;
2182 : p = pnext;
2183 176 : while (p < pend)
2184 : {
2185 158 : c = *p;
2186 158 : if (c == ' ' || c == '\t')
2187 : break;
2188 157 : if (c > ' ' && c <= 0x7f)
2189 : {
2190 : // ASCII non-space character.
2191 157 : ++p;
2192 157 : continue;
2193 : }
2194 0 : pnext = this->advance_one_utf8_char(p, &c, &issued_error);
2195 0 : if (issued_error)
2196 : return;
2197 0 : if (Lex::is_unicode_space(c))
2198 : break;
2199 : p = pnext;
2200 : }
2201 :
2202 19 : this->embeds_.push_back(std::string(start, p - start));
2203 : }
2204 : }
2205 : }
2206 :
2207 : // The Unicode tables use this struct.
2208 :
2209 : struct Unicode_range
2210 : {
2211 : // The low end of the range.
2212 : unsigned int low;
2213 : // The high end of the range.
2214 : unsigned int high;
2215 : // The stride. This entries represents low, low + stride, low + 2 *
2216 : // stride, etc., up to high.
2217 : unsigned int stride;
2218 : };
2219 :
2220 : // A table of whitespace characters--Unicode code points classified as
2221 : // "Space", "C" locale whitespace characters, the "next line" control
2222 : // character (0085), the line separator (2028), the paragraph
2223 : // separator (2029), and the "zero-width non-break space" (feff).
2224 :
2225 : static const Unicode_range unicode_space[] =
2226 : {
2227 : { 0x0009, 0x000d, 1 },
2228 : { 0x0020, 0x0020, 1 },
2229 : { 0x0085, 0x0085, 1 },
2230 : { 0x00a0, 0x00a0, 1 },
2231 : { 0x1680, 0x1680, 1 },
2232 : { 0x180e, 0x180e, 1 },
2233 : { 0x2000, 0x200a, 1 },
2234 : { 0x2028, 0x2029, 1 },
2235 : { 0x202f, 0x202f, 1 },
2236 : { 0x205f, 0x205f, 1 },
2237 : { 0x3000, 0x3000, 1 },
2238 : { 0xfeff, 0xfeff, 1 },
2239 : };
2240 :
2241 : // A table of Unicode digits--Unicode code points classified as
2242 : // "Digit".
2243 :
2244 : static const Unicode_range unicode_digits[] =
2245 : {
2246 : { 0x0030, 0x0039, 1},
2247 : { 0x0660, 0x0669, 1},
2248 : { 0x06f0, 0x06f9, 1},
2249 : { 0x07c0, 0x07c9, 1},
2250 : { 0x0966, 0x096f, 1},
2251 : { 0x09e6, 0x09ef, 1},
2252 : { 0x0a66, 0x0a6f, 1},
2253 : { 0x0ae6, 0x0aef, 1},
2254 : { 0x0b66, 0x0b6f, 1},
2255 : { 0x0be6, 0x0bef, 1},
2256 : { 0x0c66, 0x0c6f, 1},
2257 : { 0x0ce6, 0x0cef, 1},
2258 : { 0x0d66, 0x0d6f, 1},
2259 : { 0x0e50, 0x0e59, 1},
2260 : { 0x0ed0, 0x0ed9, 1},
2261 : { 0x0f20, 0x0f29, 1},
2262 : { 0x1040, 0x1049, 1},
2263 : { 0x17e0, 0x17e9, 1},
2264 : { 0x1810, 0x1819, 1},
2265 : { 0x1946, 0x194f, 1},
2266 : { 0x19d0, 0x19d9, 1},
2267 : { 0x1b50, 0x1b59, 1},
2268 : { 0xff10, 0xff19, 1},
2269 : { 0x104a0, 0x104a9, 1},
2270 : { 0x1d7ce, 0x1d7ff, 1},
2271 : };
2272 :
2273 : // A table of Unicode letters--Unicode code points classified as
2274 : // "Letter".
2275 :
2276 : static const Unicode_range unicode_letters[] =
2277 : {
2278 : { 0x0041, 0x005a, 1},
2279 : { 0x0061, 0x007a, 1},
2280 : { 0x00aa, 0x00b5, 11},
2281 : { 0x00ba, 0x00c0, 6},
2282 : { 0x00c1, 0x00d6, 1},
2283 : { 0x00d8, 0x00f6, 1},
2284 : { 0x00f8, 0x02c1, 1},
2285 : { 0x02c6, 0x02d1, 1},
2286 : { 0x02e0, 0x02e4, 1},
2287 : { 0x02ec, 0x02ee, 2},
2288 : { 0x0370, 0x0374, 1},
2289 : { 0x0376, 0x0377, 1},
2290 : { 0x037a, 0x037d, 1},
2291 : { 0x037f, 0x0386, 7},
2292 : { 0x0388, 0x038a, 1},
2293 : { 0x038c, 0x038e, 2},
2294 : { 0x038f, 0x03a1, 1},
2295 : { 0x03a3, 0x03f5, 1},
2296 : { 0x03f7, 0x0481, 1},
2297 : { 0x048a, 0x052f, 1},
2298 : { 0x0531, 0x0556, 1},
2299 : { 0x0559, 0x0561, 8},
2300 : { 0x0562, 0x0587, 1},
2301 : { 0x05d0, 0x05ea, 1},
2302 : { 0x05f0, 0x05f2, 1},
2303 : { 0x0620, 0x064a, 1},
2304 : { 0x066e, 0x066f, 1},
2305 : { 0x0671, 0x06d3, 1},
2306 : { 0x06d5, 0x06e5, 16},
2307 : { 0x06e6, 0x06ee, 8},
2308 : { 0x06ef, 0x06fa, 11},
2309 : { 0x06fb, 0x06fc, 1},
2310 : { 0x06ff, 0x0710, 17},
2311 : { 0x0712, 0x072f, 1},
2312 : { 0x074d, 0x07a5, 1},
2313 : { 0x07b1, 0x07ca, 25},
2314 : { 0x07cb, 0x07ea, 1},
2315 : { 0x07f4, 0x07f5, 1},
2316 : { 0x07fa, 0x0800, 6},
2317 : { 0x0801, 0x0815, 1},
2318 : { 0x081a, 0x0824, 10},
2319 : { 0x0828, 0x0840, 24},
2320 : { 0x0841, 0x0858, 1},
2321 : { 0x08a0, 0x08b4, 1},
2322 : { 0x0904, 0x0939, 1},
2323 : { 0x093d, 0x0950, 19},
2324 : { 0x0958, 0x0961, 1},
2325 : { 0x0971, 0x0980, 1},
2326 : { 0x0985, 0x098c, 1},
2327 : { 0x098f, 0x0990, 1},
2328 : { 0x0993, 0x09a8, 1},
2329 : { 0x09aa, 0x09b0, 1},
2330 : { 0x09b2, 0x09b6, 4},
2331 : { 0x09b7, 0x09b9, 1},
2332 : { 0x09bd, 0x09ce, 17},
2333 : { 0x09dc, 0x09dd, 1},
2334 : { 0x09df, 0x09e1, 1},
2335 : { 0x09f0, 0x09f1, 1},
2336 : { 0x0a05, 0x0a0a, 1},
2337 : { 0x0a0f, 0x0a10, 1},
2338 : { 0x0a13, 0x0a28, 1},
2339 : { 0x0a2a, 0x0a30, 1},
2340 : { 0x0a32, 0x0a33, 1},
2341 : { 0x0a35, 0x0a36, 1},
2342 : { 0x0a38, 0x0a39, 1},
2343 : { 0x0a59, 0x0a5c, 1},
2344 : { 0x0a5e, 0x0a72, 20},
2345 : { 0x0a73, 0x0a74, 1},
2346 : { 0x0a85, 0x0a8d, 1},
2347 : { 0x0a8f, 0x0a91, 1},
2348 : { 0x0a93, 0x0aa8, 1},
2349 : { 0x0aaa, 0x0ab0, 1},
2350 : { 0x0ab2, 0x0ab3, 1},
2351 : { 0x0ab5, 0x0ab9, 1},
2352 : { 0x0abd, 0x0ad0, 19},
2353 : { 0x0ae0, 0x0ae1, 1},
2354 : { 0x0af9, 0x0b05, 12},
2355 : { 0x0b06, 0x0b0c, 1},
2356 : { 0x0b0f, 0x0b10, 1},
2357 : { 0x0b13, 0x0b28, 1},
2358 : { 0x0b2a, 0x0b30, 1},
2359 : { 0x0b32, 0x0b33, 1},
2360 : { 0x0b35, 0x0b39, 1},
2361 : { 0x0b3d, 0x0b5c, 31},
2362 : { 0x0b5d, 0x0b5f, 2},
2363 : { 0x0b60, 0x0b61, 1},
2364 : { 0x0b71, 0x0b83, 18},
2365 : { 0x0b85, 0x0b8a, 1},
2366 : { 0x0b8e, 0x0b90, 1},
2367 : { 0x0b92, 0x0b95, 1},
2368 : { 0x0b99, 0x0b9a, 1},
2369 : { 0x0b9c, 0x0b9e, 2},
2370 : { 0x0b9f, 0x0ba3, 4},
2371 : { 0x0ba4, 0x0ba8, 4},
2372 : { 0x0ba9, 0x0baa, 1},
2373 : { 0x0bae, 0x0bb9, 1},
2374 : { 0x0bd0, 0x0c05, 53},
2375 : { 0x0c06, 0x0c0c, 1},
2376 : { 0x0c0e, 0x0c10, 1},
2377 : { 0x0c12, 0x0c28, 1},
2378 : { 0x0c2a, 0x0c39, 1},
2379 : { 0x0c3d, 0x0c58, 27},
2380 : { 0x0c59, 0x0c5a, 1},
2381 : { 0x0c60, 0x0c61, 1},
2382 : { 0x0c85, 0x0c8c, 1},
2383 : { 0x0c8e, 0x0c90, 1},
2384 : { 0x0c92, 0x0ca8, 1},
2385 : { 0x0caa, 0x0cb3, 1},
2386 : { 0x0cb5, 0x0cb9, 1},
2387 : { 0x0cbd, 0x0cde, 33},
2388 : { 0x0ce0, 0x0ce1, 1},
2389 : { 0x0cf1, 0x0cf2, 1},
2390 : { 0x0d05, 0x0d0c, 1},
2391 : { 0x0d0e, 0x0d10, 1},
2392 : { 0x0d12, 0x0d3a, 1},
2393 : { 0x0d3d, 0x0d5f, 17},
2394 : { 0x0d60, 0x0d61, 1},
2395 : { 0x0d7a, 0x0d7f, 1},
2396 : { 0x0d85, 0x0d96, 1},
2397 : { 0x0d9a, 0x0db1, 1},
2398 : { 0x0db3, 0x0dbb, 1},
2399 : { 0x0dbd, 0x0dc0, 3},
2400 : { 0x0dc1, 0x0dc6, 1},
2401 : { 0x0e01, 0x0e30, 1},
2402 : { 0x0e32, 0x0e33, 1},
2403 : { 0x0e40, 0x0e46, 1},
2404 : { 0x0e81, 0x0e82, 1},
2405 : { 0x0e84, 0x0e87, 3},
2406 : { 0x0e88, 0x0e8a, 2},
2407 : { 0x0e8d, 0x0e94, 7},
2408 : { 0x0e95, 0x0e97, 1},
2409 : { 0x0e99, 0x0e9f, 1},
2410 : { 0x0ea1, 0x0ea3, 1},
2411 : { 0x0ea5, 0x0ea7, 2},
2412 : { 0x0eaa, 0x0eab, 1},
2413 : { 0x0ead, 0x0eb0, 1},
2414 : { 0x0eb2, 0x0eb3, 1},
2415 : { 0x0ebd, 0x0ec0, 3},
2416 : { 0x0ec1, 0x0ec4, 1},
2417 : { 0x0ec6, 0x0edc, 22},
2418 : { 0x0edd, 0x0edf, 1},
2419 : { 0x0f00, 0x0f40, 64},
2420 : { 0x0f41, 0x0f47, 1},
2421 : { 0x0f49, 0x0f6c, 1},
2422 : { 0x0f88, 0x0f8c, 1},
2423 : { 0x1000, 0x102a, 1},
2424 : { 0x103f, 0x1050, 17},
2425 : { 0x1051, 0x1055, 1},
2426 : { 0x105a, 0x105d, 1},
2427 : { 0x1061, 0x1065, 4},
2428 : { 0x1066, 0x106e, 8},
2429 : { 0x106f, 0x1070, 1},
2430 : { 0x1075, 0x1081, 1},
2431 : { 0x108e, 0x10a0, 18},
2432 : { 0x10a1, 0x10c5, 1},
2433 : { 0x10c7, 0x10cd, 6},
2434 : { 0x10d0, 0x10fa, 1},
2435 : { 0x10fc, 0x1248, 1},
2436 : { 0x124a, 0x124d, 1},
2437 : { 0x1250, 0x1256, 1},
2438 : { 0x1258, 0x125a, 2},
2439 : { 0x125b, 0x125d, 1},
2440 : { 0x1260, 0x1288, 1},
2441 : { 0x128a, 0x128d, 1},
2442 : { 0x1290, 0x12b0, 1},
2443 : { 0x12b2, 0x12b5, 1},
2444 : { 0x12b8, 0x12be, 1},
2445 : { 0x12c0, 0x12c2, 2},
2446 : { 0x12c3, 0x12c5, 1},
2447 : { 0x12c8, 0x12d6, 1},
2448 : { 0x12d8, 0x1310, 1},
2449 : { 0x1312, 0x1315, 1},
2450 : { 0x1318, 0x135a, 1},
2451 : { 0x1380, 0x138f, 1},
2452 : { 0x13a0, 0x13f5, 1},
2453 : { 0x13f8, 0x13fd, 1},
2454 : { 0x1401, 0x166c, 1},
2455 : { 0x166f, 0x167f, 1},
2456 : { 0x1681, 0x169a, 1},
2457 : { 0x16a0, 0x16ea, 1},
2458 : { 0x16f1, 0x16f8, 1},
2459 : { 0x1700, 0x170c, 1},
2460 : { 0x170e, 0x1711, 1},
2461 : { 0x1720, 0x1731, 1},
2462 : { 0x1740, 0x1751, 1},
2463 : { 0x1760, 0x176c, 1},
2464 : { 0x176e, 0x1770, 1},
2465 : { 0x1780, 0x17b3, 1},
2466 : { 0x17d7, 0x17dc, 5},
2467 : { 0x1820, 0x1877, 1},
2468 : { 0x1880, 0x18a8, 1},
2469 : { 0x18aa, 0x18b0, 6},
2470 : { 0x18b1, 0x18f5, 1},
2471 : { 0x1900, 0x191e, 1},
2472 : { 0x1950, 0x196d, 1},
2473 : { 0x1970, 0x1974, 1},
2474 : { 0x1980, 0x19ab, 1},
2475 : { 0x19b0, 0x19c9, 1},
2476 : { 0x1a00, 0x1a16, 1},
2477 : { 0x1a20, 0x1a54, 1},
2478 : { 0x1aa7, 0x1b05, 94},
2479 : { 0x1b06, 0x1b33, 1},
2480 : { 0x1b45, 0x1b4b, 1},
2481 : { 0x1b83, 0x1ba0, 1},
2482 : { 0x1bae, 0x1baf, 1},
2483 : { 0x1bba, 0x1be5, 1},
2484 : { 0x1c00, 0x1c23, 1},
2485 : { 0x1c4d, 0x1c4f, 1},
2486 : { 0x1c5a, 0x1c7d, 1},
2487 : { 0x1ce9, 0x1cec, 1},
2488 : { 0x1cee, 0x1cf1, 1},
2489 : { 0x1cf5, 0x1cf6, 1},
2490 : { 0x1d00, 0x1dbf, 1},
2491 : { 0x1e00, 0x1f15, 1},
2492 : { 0x1f18, 0x1f1d, 1},
2493 : { 0x1f20, 0x1f45, 1},
2494 : { 0x1f48, 0x1f4d, 1},
2495 : { 0x1f50, 0x1f57, 1},
2496 : { 0x1f59, 0x1f5f, 2},
2497 : { 0x1f60, 0x1f7d, 1},
2498 : { 0x1f80, 0x1fb4, 1},
2499 : { 0x1fb6, 0x1fbc, 1},
2500 : { 0x1fbe, 0x1fc2, 4},
2501 : { 0x1fc3, 0x1fc4, 1},
2502 : { 0x1fc6, 0x1fcc, 1},
2503 : { 0x1fd0, 0x1fd3, 1},
2504 : { 0x1fd6, 0x1fdb, 1},
2505 : { 0x1fe0, 0x1fec, 1},
2506 : { 0x1ff2, 0x1ff4, 1},
2507 : { 0x1ff6, 0x1ffc, 1},
2508 : { 0x2071, 0x207f, 14},
2509 : { 0x2090, 0x209c, 1},
2510 : { 0x2102, 0x2107, 5},
2511 : { 0x210a, 0x2113, 1},
2512 : { 0x2115, 0x2119, 4},
2513 : { 0x211a, 0x211d, 1},
2514 : { 0x2124, 0x212a, 2},
2515 : { 0x212b, 0x212d, 1},
2516 : { 0x212f, 0x2139, 1},
2517 : { 0x213c, 0x213f, 1},
2518 : { 0x2145, 0x2149, 1},
2519 : { 0x214e, 0x2183, 53},
2520 : { 0x2184, 0x2c00, 2684},
2521 : { 0x2c01, 0x2c2e, 1},
2522 : { 0x2c30, 0x2c5e, 1},
2523 : { 0x2c60, 0x2ce4, 1},
2524 : { 0x2ceb, 0x2cee, 1},
2525 : { 0x2cf2, 0x2cf3, 1},
2526 : { 0x2d00, 0x2d25, 1},
2527 : { 0x2d27, 0x2d2d, 6},
2528 : { 0x2d30, 0x2d67, 1},
2529 : { 0x2d6f, 0x2d80, 17},
2530 : { 0x2d81, 0x2d96, 1},
2531 : { 0x2da0, 0x2da6, 1},
2532 : { 0x2da8, 0x2dae, 1},
2533 : { 0x2db0, 0x2db6, 1},
2534 : { 0x2db8, 0x2dbe, 1},
2535 : { 0x2dc0, 0x2dc6, 1},
2536 : { 0x2dc8, 0x2dce, 1},
2537 : { 0x2dd0, 0x2dd6, 1},
2538 : { 0x2dd8, 0x2dde, 1},
2539 : { 0x2e2f, 0x3005, 470},
2540 : { 0x3006, 0x3031, 43},
2541 : { 0x3032, 0x3035, 1},
2542 : { 0x303b, 0x303c, 1},
2543 : { 0x3041, 0x3096, 1},
2544 : { 0x309d, 0x309f, 1},
2545 : { 0x30a1, 0x30fa, 1},
2546 : { 0x30fc, 0x30ff, 1},
2547 : { 0x3105, 0x312d, 1},
2548 : { 0x3131, 0x318e, 1},
2549 : { 0x31a0, 0x31ba, 1},
2550 : { 0x31f0, 0x31ff, 1},
2551 : { 0x3400, 0x4db5, 1},
2552 : { 0x4e00, 0x9fd5, 1},
2553 : { 0xa000, 0xa48c, 1},
2554 : { 0xa4d0, 0xa4fd, 1},
2555 : { 0xa500, 0xa60c, 1},
2556 : { 0xa610, 0xa61f, 1},
2557 : { 0xa62a, 0xa62b, 1},
2558 : { 0xa640, 0xa66e, 1},
2559 : { 0xa67f, 0xa69d, 1},
2560 : { 0xa6a0, 0xa6e5, 1},
2561 : { 0xa717, 0xa71f, 1},
2562 : { 0xa722, 0xa788, 1},
2563 : { 0xa78b, 0xa7ad, 1},
2564 : { 0xa7b0, 0xa7b7, 1},
2565 : { 0xa7f7, 0xa801, 1},
2566 : { 0xa803, 0xa805, 1},
2567 : { 0xa807, 0xa80a, 1},
2568 : { 0xa80c, 0xa822, 1},
2569 : { 0xa840, 0xa873, 1},
2570 : { 0xa882, 0xa8b3, 1},
2571 : { 0xa8f2, 0xa8f7, 1},
2572 : { 0xa8fb, 0xa8fd, 2},
2573 : { 0xa90a, 0xa925, 1},
2574 : { 0xa930, 0xa946, 1},
2575 : { 0xa960, 0xa97c, 1},
2576 : { 0xa984, 0xa9b2, 1},
2577 : { 0xa9cf, 0xa9e0, 17},
2578 : { 0xa9e1, 0xa9e4, 1},
2579 : { 0xa9e6, 0xa9ef, 1},
2580 : { 0xa9fa, 0xa9fe, 1},
2581 : { 0xaa00, 0xaa28, 1},
2582 : { 0xaa40, 0xaa42, 1},
2583 : { 0xaa44, 0xaa4b, 1},
2584 : { 0xaa60, 0xaa76, 1},
2585 : { 0xaa7a, 0xaa7e, 4},
2586 : { 0xaa7f, 0xaaaf, 1},
2587 : { 0xaab1, 0xaab5, 4},
2588 : { 0xaab6, 0xaab9, 3},
2589 : { 0xaaba, 0xaabd, 1},
2590 : { 0xaac0, 0xaac2, 2},
2591 : { 0xaadb, 0xaadd, 1},
2592 : { 0xaae0, 0xaaea, 1},
2593 : { 0xaaf2, 0xaaf4, 1},
2594 : { 0xab01, 0xab06, 1},
2595 : { 0xab09, 0xab0e, 1},
2596 : { 0xab11, 0xab16, 1},
2597 : { 0xab20, 0xab26, 1},
2598 : { 0xab28, 0xab2e, 1},
2599 : { 0xab30, 0xab5a, 1},
2600 : { 0xab5c, 0xab65, 1},
2601 : { 0xab70, 0xabe2, 1},
2602 : { 0xac00, 0xd7a3, 1},
2603 : { 0xd7b0, 0xd7c6, 1},
2604 : { 0xd7cb, 0xd7fb, 1},
2605 : { 0xf900, 0xfa6d, 1},
2606 : { 0xfa70, 0xfad9, 1},
2607 : { 0xfb00, 0xfb06, 1},
2608 : { 0xfb13, 0xfb17, 1},
2609 : { 0xfb1d, 0xfb1f, 2},
2610 : { 0xfb20, 0xfb28, 1},
2611 : { 0xfb2a, 0xfb36, 1},
2612 : { 0xfb38, 0xfb3c, 1},
2613 : { 0xfb3e, 0xfb40, 2},
2614 : { 0xfb41, 0xfb43, 2},
2615 : { 0xfb44, 0xfb46, 2},
2616 : { 0xfb47, 0xfbb1, 1},
2617 : { 0xfbd3, 0xfd3d, 1},
2618 : { 0xfd50, 0xfd8f, 1},
2619 : { 0xfd92, 0xfdc7, 1},
2620 : { 0xfdf0, 0xfdfb, 1},
2621 : { 0xfe70, 0xfe74, 1},
2622 : { 0xfe76, 0xfefc, 1},
2623 : { 0xff21, 0xff3a, 1},
2624 : { 0xff41, 0xff5a, 1},
2625 : { 0xff66, 0xffbe, 1},
2626 : { 0xffc2, 0xffc7, 1},
2627 : { 0xffca, 0xffcf, 1},
2628 : { 0xffd2, 0xffd7, 1},
2629 : { 0xffda, 0xffdc, 1},
2630 : { 0x10000, 0x1000b, 1},
2631 : { 0x1000d, 0x10026, 1},
2632 : { 0x10028, 0x1003a, 1},
2633 : { 0x1003c, 0x1003d, 1},
2634 : { 0x1003f, 0x1004d, 1},
2635 : { 0x10050, 0x1005d, 1},
2636 : { 0x10080, 0x100fa, 1},
2637 : { 0x10280, 0x1029c, 1},
2638 : { 0x102a0, 0x102d0, 1},
2639 : { 0x10300, 0x1031f, 1},
2640 : { 0x10330, 0x10340, 1},
2641 : { 0x10342, 0x10349, 1},
2642 : { 0x10350, 0x10375, 1},
2643 : { 0x10380, 0x1039d, 1},
2644 : { 0x103a0, 0x103c3, 1},
2645 : { 0x103c8, 0x103cf, 1},
2646 : { 0x10400, 0x1049d, 1},
2647 : { 0x10500, 0x10527, 1},
2648 : { 0x10530, 0x10563, 1},
2649 : { 0x10600, 0x10736, 1},
2650 : { 0x10740, 0x10755, 1},
2651 : { 0x10760, 0x10767, 1},
2652 : { 0x10800, 0x10805, 1},
2653 : { 0x10808, 0x1080a, 2},
2654 : { 0x1080b, 0x10835, 1},
2655 : { 0x10837, 0x10838, 1},
2656 : { 0x1083c, 0x1083f, 3},
2657 : { 0x10840, 0x10855, 1},
2658 : { 0x10860, 0x10876, 1},
2659 : { 0x10880, 0x1089e, 1},
2660 : { 0x108e0, 0x108f2, 1},
2661 : { 0x108f4, 0x108f5, 1},
2662 : { 0x10900, 0x10915, 1},
2663 : { 0x10920, 0x10939, 1},
2664 : { 0x10980, 0x109b7, 1},
2665 : { 0x109be, 0x109bf, 1},
2666 : { 0x10a00, 0x10a10, 16},
2667 : { 0x10a11, 0x10a13, 1},
2668 : { 0x10a15, 0x10a17, 1},
2669 : { 0x10a19, 0x10a33, 1},
2670 : { 0x10a60, 0x10a7c, 1},
2671 : { 0x10a80, 0x10a9c, 1},
2672 : { 0x10ac0, 0x10ac7, 1},
2673 : { 0x10ac9, 0x10ae4, 1},
2674 : { 0x10b00, 0x10b35, 1},
2675 : { 0x10b40, 0x10b55, 1},
2676 : { 0x10b60, 0x10b72, 1},
2677 : { 0x10b80, 0x10b91, 1},
2678 : { 0x10c00, 0x10c48, 1},
2679 : { 0x10c80, 0x10cb2, 1},
2680 : { 0x10cc0, 0x10cf2, 1},
2681 : { 0x11003, 0x11037, 1},
2682 : { 0x11083, 0x110af, 1},
2683 : { 0x110d0, 0x110e8, 1},
2684 : { 0x11103, 0x11126, 1},
2685 : { 0x11150, 0x11172, 1},
2686 : { 0x11176, 0x11183, 13},
2687 : { 0x11184, 0x111b2, 1},
2688 : { 0x111c1, 0x111c4, 1},
2689 : { 0x111da, 0x111dc, 2},
2690 : { 0x11200, 0x11211, 1},
2691 : { 0x11213, 0x1122b, 1},
2692 : { 0x11280, 0x11286, 1},
2693 : { 0x11288, 0x1128a, 2},
2694 : { 0x1128b, 0x1128d, 1},
2695 : { 0x1128f, 0x1129d, 1},
2696 : { 0x1129f, 0x112a8, 1},
2697 : { 0x112b0, 0x112de, 1},
2698 : { 0x11305, 0x1130c, 1},
2699 : { 0x1130f, 0x11310, 1},
2700 : { 0x11313, 0x11328, 1},
2701 : { 0x1132a, 0x11330, 1},
2702 : { 0x11332, 0x11333, 1},
2703 : { 0x11335, 0x11339, 1},
2704 : { 0x1133d, 0x11350, 19},
2705 : { 0x1135d, 0x11361, 1},
2706 : { 0x11480, 0x114af, 1},
2707 : { 0x114c4, 0x114c5, 1},
2708 : { 0x114c7, 0x11580, 185},
2709 : { 0x11581, 0x115ae, 1},
2710 : { 0x115d8, 0x115db, 1},
2711 : { 0x11600, 0x1162f, 1},
2712 : { 0x11644, 0x11680, 60},
2713 : { 0x11681, 0x116aa, 1},
2714 : { 0x11700, 0x11719, 1},
2715 : { 0x118a0, 0x118df, 1},
2716 : { 0x118ff, 0x11ac0, 449},
2717 : { 0x11ac1, 0x11af8, 1},
2718 : { 0x12000, 0x12399, 1},
2719 : { 0x12480, 0x12543, 1},
2720 : { 0x13000, 0x1342e, 1},
2721 : { 0x14400, 0x14646, 1},
2722 : { 0x16800, 0x16a38, 1},
2723 : { 0x16a40, 0x16a5e, 1},
2724 : { 0x16ad0, 0x16aed, 1},
2725 : { 0x16b00, 0x16b2f, 1},
2726 : { 0x16b40, 0x16b43, 1},
2727 : { 0x16b63, 0x16b77, 1},
2728 : { 0x16b7d, 0x16b8f, 1},
2729 : { 0x16f00, 0x16f44, 1},
2730 : { 0x16f50, 0x16f93, 67},
2731 : { 0x16f94, 0x16f9f, 1},
2732 : { 0x1b000, 0x1b001, 1},
2733 : { 0x1bc00, 0x1bc6a, 1},
2734 : { 0x1bc70, 0x1bc7c, 1},
2735 : { 0x1bc80, 0x1bc88, 1},
2736 : { 0x1bc90, 0x1bc99, 1},
2737 : { 0x1d400, 0x1d454, 1},
2738 : { 0x1d456, 0x1d49c, 1},
2739 : { 0x1d49e, 0x1d49f, 1},
2740 : { 0x1d4a2, 0x1d4a5, 3},
2741 : { 0x1d4a6, 0x1d4a9, 3},
2742 : { 0x1d4aa, 0x1d4ac, 1},
2743 : { 0x1d4ae, 0x1d4b9, 1},
2744 : { 0x1d4bb, 0x1d4bd, 2},
2745 : { 0x1d4be, 0x1d4c3, 1},
2746 : { 0x1d4c5, 0x1d505, 1},
2747 : { 0x1d507, 0x1d50a, 1},
2748 : { 0x1d50d, 0x1d514, 1},
2749 : { 0x1d516, 0x1d51c, 1},
2750 : { 0x1d51e, 0x1d539, 1},
2751 : { 0x1d53b, 0x1d53e, 1},
2752 : { 0x1d540, 0x1d544, 1},
2753 : { 0x1d546, 0x1d54a, 4},
2754 : { 0x1d54b, 0x1d550, 1},
2755 : { 0x1d552, 0x1d6a5, 1},
2756 : { 0x1d6a8, 0x1d6c0, 1},
2757 : { 0x1d6c2, 0x1d6da, 1},
2758 : { 0x1d6dc, 0x1d6fa, 1},
2759 : { 0x1d6fc, 0x1d714, 1},
2760 : { 0x1d716, 0x1d734, 1},
2761 : { 0x1d736, 0x1d74e, 1},
2762 : { 0x1d750, 0x1d76e, 1},
2763 : { 0x1d770, 0x1d788, 1},
2764 : { 0x1d78a, 0x1d7a8, 1},
2765 : { 0x1d7aa, 0x1d7c2, 1},
2766 : { 0x1d7c4, 0x1d7cb, 1},
2767 : { 0x1e800, 0x1e8c4, 1},
2768 : { 0x1ee00, 0x1ee03, 1},
2769 : { 0x1ee05, 0x1ee1f, 1},
2770 : { 0x1ee21, 0x1ee22, 1},
2771 : { 0x1ee24, 0x1ee27, 3},
2772 : { 0x1ee29, 0x1ee32, 1},
2773 : { 0x1ee34, 0x1ee37, 1},
2774 : { 0x1ee39, 0x1ee3b, 2},
2775 : { 0x1ee42, 0x1ee47, 5},
2776 : { 0x1ee49, 0x1ee4d, 2},
2777 : { 0x1ee4e, 0x1ee4f, 1},
2778 : { 0x1ee51, 0x1ee52, 1},
2779 : { 0x1ee54, 0x1ee57, 3},
2780 : { 0x1ee59, 0x1ee61, 2},
2781 : { 0x1ee62, 0x1ee64, 2},
2782 : { 0x1ee67, 0x1ee6a, 1},
2783 : { 0x1ee6c, 0x1ee72, 1},
2784 : { 0x1ee74, 0x1ee77, 1},
2785 : { 0x1ee79, 0x1ee7c, 1},
2786 : { 0x1ee7e, 0x1ee80, 2},
2787 : { 0x1ee81, 0x1ee89, 1},
2788 : { 0x1ee8b, 0x1ee9b, 1},
2789 : { 0x1eea1, 0x1eea3, 1},
2790 : { 0x1eea5, 0x1eea9, 1},
2791 : { 0x1eeab, 0x1eebb, 1},
2792 : { 0x20000, 0x2a6d6, 1},
2793 : { 0x2a700, 0x2b734, 1},
2794 : { 0x2b740, 0x2b81d, 1},
2795 : { 0x2b820, 0x2cea1, 1},
2796 : { 0x2f800, 0x2fa1d, 1},
2797 : };
2798 :
2799 : // A table of Unicode uppercase letters--Unicode code points
2800 : // classified as "Letter, uppercase".
2801 :
2802 : static const Unicode_range unicode_uppercase_letters[] =
2803 : {
2804 : { 0x0041, 0x005a, 1},
2805 : { 0x00c0, 0x00d6, 1},
2806 : { 0x00d8, 0x00de, 1},
2807 : { 0x0100, 0x0136, 2},
2808 : { 0x0139, 0x0147, 2},
2809 : { 0x014a, 0x0178, 2},
2810 : { 0x0179, 0x017d, 2},
2811 : { 0x0181, 0x0182, 1},
2812 : { 0x0184, 0x0186, 2},
2813 : { 0x0187, 0x0189, 2},
2814 : { 0x018a, 0x018b, 1},
2815 : { 0x018e, 0x0191, 1},
2816 : { 0x0193, 0x0194, 1},
2817 : { 0x0196, 0x0198, 1},
2818 : { 0x019c, 0x019d, 1},
2819 : { 0x019f, 0x01a0, 1},
2820 : { 0x01a2, 0x01a6, 2},
2821 : { 0x01a7, 0x01a9, 2},
2822 : { 0x01ac, 0x01ae, 2},
2823 : { 0x01af, 0x01b1, 2},
2824 : { 0x01b2, 0x01b3, 1},
2825 : { 0x01b5, 0x01b7, 2},
2826 : { 0x01b8, 0x01bc, 4},
2827 : { 0x01c4, 0x01cd, 3},
2828 : { 0x01cf, 0x01db, 2},
2829 : { 0x01de, 0x01ee, 2},
2830 : { 0x01f1, 0x01f4, 3},
2831 : { 0x01f6, 0x01f8, 1},
2832 : { 0x01fa, 0x0232, 2},
2833 : { 0x023a, 0x023b, 1},
2834 : { 0x023d, 0x023e, 1},
2835 : { 0x0241, 0x0243, 2},
2836 : { 0x0244, 0x0246, 1},
2837 : { 0x0248, 0x024e, 2},
2838 : { 0x0370, 0x0372, 2},
2839 : { 0x0376, 0x037f, 9},
2840 : { 0x0386, 0x0388, 2},
2841 : { 0x0389, 0x038a, 1},
2842 : { 0x038c, 0x038e, 2},
2843 : { 0x038f, 0x0391, 2},
2844 : { 0x0392, 0x03a1, 1},
2845 : { 0x03a3, 0x03ab, 1},
2846 : { 0x03cf, 0x03d2, 3},
2847 : { 0x03d3, 0x03d4, 1},
2848 : { 0x03d8, 0x03ee, 2},
2849 : { 0x03f4, 0x03f7, 3},
2850 : { 0x03f9, 0x03fa, 1},
2851 : { 0x03fd, 0x042f, 1},
2852 : { 0x0460, 0x0480, 2},
2853 : { 0x048a, 0x04c0, 2},
2854 : { 0x04c1, 0x04cd, 2},
2855 : { 0x04d0, 0x052e, 2},
2856 : { 0x0531, 0x0556, 1},
2857 : { 0x10a0, 0x10c5, 1},
2858 : { 0x10c7, 0x10cd, 6},
2859 : { 0x1e00, 0x1e94, 2},
2860 : { 0x1e9e, 0x1efe, 2},
2861 : { 0x1f08, 0x1f0f, 1},
2862 : { 0x1f18, 0x1f1d, 1},
2863 : { 0x1f28, 0x1f2f, 1},
2864 : { 0x1f38, 0x1f3f, 1},
2865 : { 0x1f48, 0x1f4d, 1},
2866 : { 0x1f59, 0x1f5f, 2},
2867 : { 0x1f68, 0x1f6f, 1},
2868 : { 0x1fb8, 0x1fbb, 1},
2869 : { 0x1fc8, 0x1fcb, 1},
2870 : { 0x1fd8, 0x1fdb, 1},
2871 : { 0x1fe8, 0x1fec, 1},
2872 : { 0x1ff8, 0x1ffb, 1},
2873 : { 0x2102, 0x2107, 5},
2874 : { 0x210b, 0x210d, 1},
2875 : { 0x2110, 0x2112, 1},
2876 : { 0x2115, 0x2119, 4},
2877 : { 0x211a, 0x211d, 1},
2878 : { 0x2124, 0x212a, 2},
2879 : { 0x212b, 0x212d, 1},
2880 : { 0x2130, 0x2133, 1},
2881 : { 0x213e, 0x213f, 1},
2882 : { 0x2145, 0x2183, 62},
2883 : { 0x2c00, 0x2c2e, 1},
2884 : { 0x2c60, 0x2c62, 2},
2885 : { 0x2c63, 0x2c64, 1},
2886 : { 0x2c67, 0x2c6d, 2},
2887 : { 0x2c6e, 0x2c70, 1},
2888 : { 0x2c72, 0x2c75, 3},
2889 : { 0x2c7e, 0x2c80, 1},
2890 : { 0x2c82, 0x2ce2, 2},
2891 : { 0x2ceb, 0x2ced, 2},
2892 : { 0x2cf2, 0xa640, 31054},
2893 : { 0xa642, 0xa66c, 2},
2894 : { 0xa680, 0xa69a, 2},
2895 : { 0xa722, 0xa72e, 2},
2896 : { 0xa732, 0xa76e, 2},
2897 : { 0xa779, 0xa77d, 2},
2898 : { 0xa77e, 0xa786, 2},
2899 : { 0xa78b, 0xa78d, 2},
2900 : { 0xa790, 0xa792, 2},
2901 : { 0xa796, 0xa7aa, 2},
2902 : { 0xa7ab, 0xa7ad, 1},
2903 : { 0xa7b0, 0xa7b1, 1},
2904 : { 0xff21, 0xff3a, 1},
2905 : { 0x10400, 0x10427, 1},
2906 : { 0x118a0, 0x118bf, 1},
2907 : { 0x1d400, 0x1d419, 1},
2908 : { 0x1d434, 0x1d44d, 1},
2909 : { 0x1d468, 0x1d481, 1},
2910 : { 0x1d49c, 0x1d49e, 2},
2911 : { 0x1d49f, 0x1d4a5, 3},
2912 : { 0x1d4a6, 0x1d4a9, 3},
2913 : { 0x1d4aa, 0x1d4ac, 1},
2914 : { 0x1d4ae, 0x1d4b5, 1},
2915 : { 0x1d4d0, 0x1d4e9, 1},
2916 : { 0x1d504, 0x1d505, 1},
2917 : { 0x1d507, 0x1d50a, 1},
2918 : { 0x1d50d, 0x1d514, 1},
2919 : { 0x1d516, 0x1d51c, 1},
2920 : { 0x1d538, 0x1d539, 1},
2921 : { 0x1d53b, 0x1d53e, 1},
2922 : { 0x1d540, 0x1d544, 1},
2923 : { 0x1d546, 0x1d54a, 4},
2924 : { 0x1d54b, 0x1d550, 1},
2925 : { 0x1d56c, 0x1d585, 1},
2926 : { 0x1d5a0, 0x1d5b9, 1},
2927 : { 0x1d5d4, 0x1d5ed, 1},
2928 : { 0x1d608, 0x1d621, 1},
2929 : { 0x1d63c, 0x1d655, 1},
2930 : { 0x1d670, 0x1d689, 1},
2931 : { 0x1d6a8, 0x1d6c0, 1},
2932 : { 0x1d6e2, 0x1d6fa, 1},
2933 : { 0x1d71c, 0x1d734, 1},
2934 : { 0x1d756, 0x1d76e, 1},
2935 : { 0x1d790, 0x1d7a8, 1},
2936 : { 0x1d7ca, 0x1d7ca, 1},
2937 : };
2938 :
2939 : // Return true if C is in RANGES.
2940 :
2941 : bool
2942 448312 : Lex::is_in_unicode_range(unsigned int c, const Unicode_range* ranges,
2943 : size_t range_size)
2944 : {
2945 448312 : if (c < 0x100)
2946 : {
2947 : // The common case is a small value, and we know that it will be
2948 : // in the first few entries of the table. Do a linear scan
2949 : // rather than a binary search.
2950 1263235 : for (size_t i = 0; i < range_size; ++i)
2951 : {
2952 1263235 : const Unicode_range* p = &ranges[i];
2953 1263235 : if (c <= p->high)
2954 : {
2955 448043 : if (c < p->low)
2956 : return false;
2957 38992 : return (c - p->low) % p->stride == 0;
2958 : }
2959 : }
2960 : return false;
2961 : }
2962 : else
2963 : {
2964 : size_t lo = 0;
2965 : size_t hi = range_size;
2966 2171 : while (lo < hi)
2967 : {
2968 2135 : size_t mid = lo + (hi - lo) / 2;
2969 2135 : const Unicode_range* p = &ranges[mid];
2970 2135 : if (c < p->low)
2971 : hi = mid;
2972 633 : else if (c > p->high)
2973 400 : lo = mid + 1;
2974 : else
2975 233 : return (c - p->low) % p->stride == 0;
2976 : }
2977 : return false;
2978 : }
2979 : }
2980 :
2981 : // Return whether C is a space character.
2982 :
2983 : bool
2984 366466 : Lex::is_unicode_space(unsigned int c)
2985 : {
2986 366466 : return Lex::is_in_unicode_range(c, unicode_space,
2987 366466 : ARRAY_SIZE(unicode_space));
2988 : }
2989 :
2990 : // Return whether C is a Unicode digit--a Unicode code point
2991 : // classified as "Digit".
2992 :
2993 : bool
2994 5 : Lex::is_unicode_digit(unsigned int c)
2995 : {
2996 5 : return Lex::is_in_unicode_range(c, unicode_digits,
2997 5 : ARRAY_SIZE(unicode_digits));
2998 : }
2999 :
3000 : // Return whether C is a Unicode letter--a Unicode code point
3001 : // classified as "Letter".
3002 :
3003 : bool
3004 39097 : Lex::is_unicode_letter(unsigned int c)
3005 : {
3006 39097 : return Lex::is_in_unicode_range(c, unicode_letters,
3007 39097 : ARRAY_SIZE(unicode_letters));
3008 : }
3009 :
3010 : // Return whether C is a Unicode uppercase letter. a Unicode code
3011 : // point classified as "Letter, uppercase".
3012 :
3013 : bool
3014 42744 : Lex::is_unicode_uppercase(unsigned int c)
3015 : {
3016 42744 : return Lex::is_in_unicode_range(c, unicode_uppercase_letters,
3017 42744 : ARRAY_SIZE(unicode_uppercase_letters));
3018 : }
3019 :
3020 : // Return whether the identifier NAME should be exported. NAME is a
3021 : // mangled name which includes only ASCII characters.
3022 :
3023 : bool
3024 0 : Lex::is_exported_mangled_name(const std::string& name)
3025 : {
3026 0 : unsigned char c = name[0];
3027 0 : if (c != '.')
3028 0 : return c >= 'A' && c <= 'Z';
3029 : else
3030 : {
3031 0 : const char* p = name.data();
3032 0 : size_t len = name.length();
3033 0 : if (len < 4 || p[1] != '.' || (p[2] != 'u' && p[2] != 'U'))
3034 : return false;
3035 0 : unsigned int ci = 0;
3036 0 : size_t want = (p[2] == 'u' ? 4 : 8);
3037 0 : if (len < want + 3)
3038 : return false;
3039 0 : for (size_t i = 3; i < want; ++i)
3040 : {
3041 0 : c = p[i];
3042 0 : if (!Lex::is_hex_digit(c))
3043 : return false;
3044 0 : ci <<= 4;
3045 0 : ci |= Lex::hex_val(c);
3046 : }
3047 0 : return Lex::is_unicode_uppercase(ci);
3048 : }
3049 : }
3050 :
3051 : // Return whether the identifier NAME should be exported. NAME is a
3052 : // an unmangled utf-8 string and may contain non-ASCII characters.
3053 :
3054 : bool
3055 38723 : Lex::is_exported_name(const std::string& name)
3056 : {
3057 38723 : unsigned int uchar;
3058 38723 : if (Lex::fetch_char(name.c_str(), &uchar) != 0)
3059 38723 : return Lex::is_unicode_letter(uchar) && Lex::is_unicode_uppercase(uchar);
3060 : return false;
3061 : }
3062 :
3063 : // Return whether the identifier NAME contains an invalid character.
3064 : // This is based on how we handle invalid characters in
3065 : // gather_identifier.
3066 :
3067 : bool
3068 3881858 : Lex::is_invalid_identifier(const std::string& name)
3069 : {
3070 3881858 : return name.find("$INVALID$") != std::string::npos;
3071 : }
|