98 |
98 |
99 /** Allow hex floating-point literals. |
99 /** Allow hex floating-point literals. |
100 */ |
100 */ |
101 private boolean allowHexFloats; |
101 private boolean allowHexFloats; |
102 |
102 |
|
103 /** Allow binary literals. |
|
104 */ |
|
105 private boolean allowBinaryLiterals; |
|
106 |
|
107 /** Allow underscores in literals. |
|
108 */ |
|
109 private boolean allowUnderscoresInLiterals; |
|
110 |
|
111 /** The source language setting. |
|
112 */ |
|
113 private Source source; |
|
114 |
103 /** The token's position, 0-based offset from beginning of text. |
115 /** The token's position, 0-based offset from beginning of text. |
104 */ |
116 */ |
105 private int pos; |
117 private int pos; |
106 |
118 |
107 /** Character position just after the last character of the token. |
119 /** Character position just after the last character of the token. |
160 /** The keyword table. */ |
172 /** The keyword table. */ |
161 private final Keywords keywords; |
173 private final Keywords keywords; |
162 |
174 |
163 /** Common code for constructors. */ |
175 /** Common code for constructors. */ |
164 private Scanner(Factory fac) { |
176 private Scanner(Factory fac) { |
165 this.log = fac.log; |
177 log = fac.log; |
166 this.names = fac.names; |
178 names = fac.names; |
167 this.keywords = fac.keywords; |
179 keywords = fac.keywords; |
168 this.allowHexFloats = fac.source.allowHexFloats(); |
180 source = fac.source; |
|
181 allowBinaryLiterals = source.allowBinaryLiterals(); |
|
182 allowHexFloats = source.allowHexFloats(); |
|
183 allowUnderscoresInLiterals = source.allowBinaryLiterals(); |
169 } |
184 } |
170 |
185 |
171 private static final boolean hexFloatsWork = hexFloatsWork(); |
186 private static final boolean hexFloatsWork = hexFloatsWork(); |
172 private static boolean hexFloatsWork() { |
187 private static boolean hexFloatsWork() { |
173 try { |
188 try { |
394 break; |
409 break; |
395 } |
410 } |
396 scanLitChar(true); |
411 scanLitChar(true); |
397 } |
412 } |
398 |
413 |
|
414 private void scanDigits(int digitRadix) { |
|
415 char saveCh; |
|
416 int savePos; |
|
417 do { |
|
418 if (ch != '_') { |
|
419 putChar(ch); |
|
420 } else { |
|
421 if (!allowUnderscoresInLiterals) { |
|
422 lexError("unsupported.underscore", source.name); |
|
423 allowUnderscoresInLiterals = true; |
|
424 } |
|
425 } |
|
426 saveCh = ch; |
|
427 savePos = bp; |
|
428 scanChar(); |
|
429 } while (digit(digitRadix) >= 0 || ch == '_'); |
|
430 if (saveCh == '_') |
|
431 lexError(savePos, "illegal.underscore"); |
|
432 } |
|
433 |
399 /** Read fractional part of hexadecimal floating point number. |
434 /** Read fractional part of hexadecimal floating point number. |
400 */ |
435 */ |
401 private void scanHexExponentAndSuffix() { |
436 private void scanHexExponentAndSuffix() { |
402 if (ch == 'p' || ch == 'P') { |
437 if (ch == 'p' || ch == 'P') { |
403 putChar(ch); |
438 putChar(ch); |
404 scanChar(); |
439 scanChar(); |
|
440 skipIllegalUnderscores(); |
405 if (ch == '+' || ch == '-') { |
441 if (ch == '+' || ch == '-') { |
406 putChar(ch); |
442 putChar(ch); |
407 scanChar(); |
443 scanChar(); |
408 } |
444 } |
|
445 skipIllegalUnderscores(); |
409 if ('0' <= ch && ch <= '9') { |
446 if ('0' <= ch && ch <= '9') { |
410 do { |
447 scanDigits(10); |
411 putChar(ch); |
|
412 scanChar(); |
|
413 } while ('0' <= ch && ch <= '9'); |
|
414 if (!allowHexFloats) { |
448 if (!allowHexFloats) { |
415 lexError("unsupported.fp.lit"); |
449 lexError("unsupported.fp.lit", source.name); |
416 allowHexFloats = true; |
450 allowHexFloats = true; |
417 } |
451 } |
418 else if (!hexFloatsWork) |
452 else if (!hexFloatsWork) |
419 lexError("unsupported.cross.fp.lit"); |
453 lexError("unsupported.cross.fp.lit"); |
420 } else |
454 } else |
436 } |
470 } |
437 |
471 |
438 /** Read fractional part of floating point number. |
472 /** Read fractional part of floating point number. |
439 */ |
473 */ |
440 private void scanFraction() { |
474 private void scanFraction() { |
441 while (digit(10) >= 0) { |
475 skipIllegalUnderscores(); |
442 putChar(ch); |
476 if ('0' <= ch && ch <= '9') { |
443 scanChar(); |
477 scanDigits(10); |
444 } |
478 } |
445 int sp1 = sp; |
479 int sp1 = sp; |
446 if (ch == 'e' || ch == 'E') { |
480 if (ch == 'e' || ch == 'E') { |
447 putChar(ch); |
481 putChar(ch); |
448 scanChar(); |
482 scanChar(); |
|
483 skipIllegalUnderscores(); |
449 if (ch == '+' || ch == '-') { |
484 if (ch == '+' || ch == '-') { |
450 putChar(ch); |
485 putChar(ch); |
451 scanChar(); |
486 scanChar(); |
452 } |
487 } |
|
488 skipIllegalUnderscores(); |
453 if ('0' <= ch && ch <= '9') { |
489 if ('0' <= ch && ch <= '9') { |
454 do { |
490 scanDigits(10); |
455 putChar(ch); |
|
456 scanChar(); |
|
457 } while ('0' <= ch && ch <= '9'); |
|
458 return; |
491 return; |
459 } |
492 } |
460 lexError("malformed.fp.lit"); |
493 lexError("malformed.fp.lit"); |
461 sp = sp1; |
494 sp = sp1; |
462 } |
495 } |
485 private void scanHexFractionAndSuffix(boolean seendigit) { |
518 private void scanHexFractionAndSuffix(boolean seendigit) { |
486 this.radix = 16; |
519 this.radix = 16; |
487 assert ch == '.'; |
520 assert ch == '.'; |
488 putChar(ch); |
521 putChar(ch); |
489 scanChar(); |
522 scanChar(); |
490 while (digit(16) >= 0) { |
523 skipIllegalUnderscores(); |
|
524 if (digit(16) >= 0) { |
491 seendigit = true; |
525 seendigit = true; |
492 putChar(ch); |
526 scanDigits(16); |
493 scanChar(); |
|
494 } |
527 } |
495 if (!seendigit) |
528 if (!seendigit) |
496 lexError("invalid.hex.number"); |
529 lexError("invalid.hex.number"); |
497 else |
530 else |
498 scanHexExponentAndSuffix(); |
531 scanHexExponentAndSuffix(); |
499 } |
532 } |
500 |
533 |
|
534 private void skipIllegalUnderscores() { |
|
535 if (ch == '_') { |
|
536 lexError(bp, "illegal.underscore"); |
|
537 while (ch == '_') |
|
538 scanChar(); |
|
539 } |
|
540 } |
|
541 |
501 /** Read a number. |
542 /** Read a number. |
502 * @param radix The radix of the number; one of 8, 10, 16. |
543 * @param radix The radix of the number; one of 2, j8, 10, 16. |
503 */ |
544 */ |
504 private void scanNumber(int radix) { |
545 private void scanNumber(int radix) { |
505 this.radix = radix; |
546 this.radix = radix; |
506 // for octal, allow base-10 digit in case it's a float literal |
547 // for octal, allow base-10 digit in case it's a float literal |
507 int digitRadix = (radix <= 10) ? 10 : 16; |
548 int digitRadix = (radix == 8 ? 10 : radix); |
508 boolean seendigit = false; |
549 boolean seendigit = false; |
509 while (digit(digitRadix) >= 0) { |
550 if (digit(digitRadix) >= 0) { |
510 seendigit = true; |
551 seendigit = true; |
511 putChar(ch); |
552 scanDigits(digitRadix); |
512 scanChar(); |
|
513 } |
553 } |
514 if (radix == 16 && ch == '.') { |
554 if (radix == 16 && ch == '.') { |
515 scanHexFractionAndSuffix(seendigit); |
555 scanHexFractionAndSuffix(seendigit); |
516 } else if (seendigit && radix == 16 && (ch == 'p' || ch == 'P')) { |
556 } else if (seendigit && radix == 16 && (ch == 'p' || ch == 'P')) { |
517 scanHexExponentAndSuffix(); |
557 scanHexExponentAndSuffix(); |
518 } else if (radix <= 10 && ch == '.') { |
558 } else if (digitRadix == 10 && ch == '.') { |
519 putChar(ch); |
559 putChar(ch); |
520 scanChar(); |
560 scanChar(); |
521 scanFractionAndSuffix(); |
561 scanFractionAndSuffix(); |
522 } else if (radix <= 10 && |
562 } else if (digitRadix == 10 && |
523 (ch == 'e' || ch == 'E' || |
563 (ch == 'e' || ch == 'E' || |
524 ch == 'f' || ch == 'F' || |
564 ch == 'f' || ch == 'F' || |
525 ch == 'd' || ch == 'D')) { |
565 ch == 'd' || ch == 'D')) { |
526 scanFractionAndSuffix(); |
566 scanFractionAndSuffix(); |
527 } else { |
567 } else { |
819 return; |
859 return; |
820 case '0': |
860 case '0': |
821 scanChar(); |
861 scanChar(); |
822 if (ch == 'x' || ch == 'X') { |
862 if (ch == 'x' || ch == 'X') { |
823 scanChar(); |
863 scanChar(); |
|
864 skipIllegalUnderscores(); |
824 if (ch == '.') { |
865 if (ch == '.') { |
825 scanHexFractionAndSuffix(false); |
866 scanHexFractionAndSuffix(false); |
826 } else if (digit(16) < 0) { |
867 } else if (digit(16) < 0) { |
827 lexError("invalid.hex.number"); |
868 lexError("invalid.hex.number"); |
828 } else { |
869 } else { |
829 scanNumber(16); |
870 scanNumber(16); |
830 } |
871 } |
|
872 } else if (ch == 'b' || ch == 'B') { |
|
873 if (!allowBinaryLiterals) { |
|
874 lexError("unsupported.binary.lit", source.name); |
|
875 allowBinaryLiterals = true; |
|
876 } |
|
877 scanChar(); |
|
878 skipIllegalUnderscores(); |
|
879 scanNumber(2); |
831 } else { |
880 } else { |
832 putChar('0'); |
881 putChar('0'); |
|
882 if (ch == '_') { |
|
883 int savePos = bp; |
|
884 do { |
|
885 scanChar(); |
|
886 } while (ch == '_'); |
|
887 if (digit(10) < 0) { |
|
888 lexError(savePos, "illegal.underscore"); |
|
889 } |
|
890 } |
833 scanNumber(8); |
891 scanNumber(8); |
834 } |
892 } |
835 return; |
893 return; |
836 case '1': case '2': case '3': case '4': |
894 case '1': case '2': case '3': case '4': |
837 case '5': case '6': case '7': case '8': case '9': |
895 case '5': case '6': case '7': case '8': case '9': |