24 */ |
24 */ |
25 |
25 |
26 package com.sun.tools.javac.parser; |
26 package com.sun.tools.javac.parser; |
27 |
27 |
28 import com.sun.tools.javac.code.Source; |
28 import com.sun.tools.javac.code.Source; |
|
29 import com.sun.tools.javac.code.Source.Feature; |
29 import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; |
30 import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; |
|
31 import com.sun.tools.javac.resources.CompilerProperties.Errors; |
30 import com.sun.tools.javac.util.*; |
32 import com.sun.tools.javac.util.*; |
|
33 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; |
31 |
34 |
32 import java.nio.CharBuffer; |
35 import java.nio.CharBuffer; |
33 |
36 |
34 import static com.sun.tools.javac.parser.Tokens.*; |
37 import static com.sun.tools.javac.parser.Tokens.*; |
35 import static com.sun.tools.javac.util.LayoutCharacters.*; |
38 import static com.sun.tools.javac.util.LayoutCharacters.*; |
44 */ |
47 */ |
45 public class JavaTokenizer { |
48 public class JavaTokenizer { |
46 |
49 |
47 private static final boolean scannerDebug = false; |
50 private static final boolean scannerDebug = false; |
48 |
51 |
49 /** Allow binary literals. |
|
50 */ |
|
51 private boolean allowBinaryLiterals; |
|
52 |
|
53 /** Allow underscores in literals. |
|
54 */ |
|
55 private boolean allowUnderscoresInLiterals; |
|
56 |
|
57 /** The source language setting. |
52 /** The source language setting. |
58 */ |
53 */ |
59 private Source source; |
54 private Source source; |
60 |
55 |
61 /** The log to be used for error reporting. |
56 /** The log to be used for error reporting. |
119 this.fac = fac; |
114 this.fac = fac; |
120 this.log = fac.log; |
115 this.log = fac.log; |
121 this.tokens = fac.tokens; |
116 this.tokens = fac.tokens; |
122 this.source = fac.source; |
117 this.source = fac.source; |
123 this.reader = reader; |
118 this.reader = reader; |
124 this.allowBinaryLiterals = source.allowBinaryLiterals(); |
119 } |
125 this.allowUnderscoresInLiterals = source.allowUnderscoresInLiterals(); |
120 |
|
121 private void checkSourceLevel(int pos, Feature feature) { |
|
122 if (!feature.allowedInSource(source)) { |
|
123 lexError(DiagnosticFlag.SOURCE_LEVEL, pos, feature.error(source.name)); |
|
124 } |
126 } |
125 } |
127 |
126 |
128 /** Report an error at the given position using the provided arguments. |
127 /** Report an error at the given position using the provided arguments. |
129 */ |
128 */ |
130 protected void lexError(int pos, String key, Object... args) { |
129 protected void lexError(int pos, JCDiagnostic.Error key) { |
131 log.error(pos, key, args); |
130 log.error(pos, key); |
|
131 tk = TokenKind.ERROR; |
|
132 errPos = pos; |
|
133 } |
|
134 |
|
135 protected void lexError(DiagnosticFlag flags, int pos, JCDiagnostic.Error key) { |
|
136 log.error(flags, pos, key); |
132 tk = TokenKind.ERROR; |
137 tk = TokenKind.ERROR; |
133 errPos = pos; |
138 errPos = pos; |
134 } |
139 } |
135 |
140 |
136 /** Read next character in character or string literal and copy into sbuf. |
141 /** Read next character in character or string literal and copy into sbuf. |
173 case '\"': |
178 case '\"': |
174 reader.putChar('\"', true); break; |
179 reader.putChar('\"', true); break; |
175 case '\\': |
180 case '\\': |
176 reader.putChar('\\', true); break; |
181 reader.putChar('\\', true); break; |
177 default: |
182 default: |
178 lexError(reader.bp, "illegal.esc.char"); |
183 lexError(reader.bp, Errors.IllegalEscChar); |
179 } |
184 } |
180 } |
185 } |
181 } else if (reader.bp != reader.buflen) { |
186 } else if (reader.bp != reader.buflen) { |
182 reader.putChar(true); |
187 reader.putChar(true); |
183 } |
188 } |
188 int savePos; |
193 int savePos; |
189 do { |
194 do { |
190 if (reader.ch != '_') { |
195 if (reader.ch != '_') { |
191 reader.putChar(false); |
196 reader.putChar(false); |
192 } else { |
197 } else { |
193 if (!allowUnderscoresInLiterals) { |
198 checkSourceLevel(pos, Feature.UNDERSCORES_IN_LITERALS); |
194 lexError(pos, "unsupported.underscore.lit", source.name); |
|
195 allowUnderscoresInLiterals = true; |
|
196 } |
|
197 } |
199 } |
198 saveCh = reader.ch; |
200 saveCh = reader.ch; |
199 savePos = reader.bp; |
201 savePos = reader.bp; |
200 reader.scanChar(); |
202 reader.scanChar(); |
201 } while (reader.digit(pos, digitRadix) >= 0 || reader.ch == '_'); |
203 } while (reader.digit(pos, digitRadix) >= 0 || reader.ch == '_'); |
202 if (saveCh == '_') |
204 if (saveCh == '_') |
203 lexError(savePos, "illegal.underscore"); |
205 lexError(savePos, Errors.IllegalUnderscore); |
204 } |
206 } |
205 |
207 |
206 /** Read fractional part of hexadecimal floating point number. |
208 /** Read fractional part of hexadecimal floating point number. |
207 */ |
209 */ |
208 private void scanHexExponentAndSuffix(int pos) { |
210 private void scanHexExponentAndSuffix(int pos) { |
214 } |
216 } |
215 skipIllegalUnderscores(); |
217 skipIllegalUnderscores(); |
216 if (reader.digit(pos, 10) >= 0) { |
218 if (reader.digit(pos, 10) >= 0) { |
217 scanDigits(pos, 10); |
219 scanDigits(pos, 10); |
218 if (!hexFloatsWork) |
220 if (!hexFloatsWork) |
219 lexError(pos, "unsupported.cross.fp.lit"); |
221 lexError(pos, Errors.UnsupportedCrossFpLit); |
220 } else |
222 } else |
221 lexError(pos, "malformed.fp.lit"); |
223 lexError(pos, Errors.MalformedFpLit); |
222 } else { |
224 } else { |
223 lexError(pos, "malformed.fp.lit"); |
225 lexError(pos, Errors.MalformedFpLit); |
224 } |
226 } |
225 if (reader.ch == 'f' || reader.ch == 'F') { |
227 if (reader.ch == 'f' || reader.ch == 'F') { |
226 reader.putChar(true); |
228 reader.putChar(true); |
227 tk = TokenKind.FLOATLITERAL; |
229 tk = TokenKind.FLOATLITERAL; |
228 radix = 16; |
230 radix = 16; |
252 skipIllegalUnderscores(); |
254 skipIllegalUnderscores(); |
253 if (reader.digit(pos, 10) >= 0) { |
255 if (reader.digit(pos, 10) >= 0) { |
254 scanDigits(pos, 10); |
256 scanDigits(pos, 10); |
255 return; |
257 return; |
256 } |
258 } |
257 lexError(pos, "malformed.fp.lit"); |
259 lexError(pos, Errors.MalformedFpLit); |
258 reader.sp = sp1; |
260 reader.sp = sp1; |
259 } |
261 } |
260 } |
262 } |
261 |
263 |
262 /** Read fractional part and 'd' or 'f' suffix of floating point number. |
264 /** Read fractional part and 'd' or 'f' suffix of floating point number. |
285 if (reader.digit(pos, 16) >= 0) { |
287 if (reader.digit(pos, 16) >= 0) { |
286 seendigit = true; |
288 seendigit = true; |
287 scanDigits(pos, 16); |
289 scanDigits(pos, 16); |
288 } |
290 } |
289 if (!seendigit) |
291 if (!seendigit) |
290 lexError(pos, "invalid.hex.number"); |
292 lexError(pos, Errors.InvalidHexNumber); |
291 else |
293 else |
292 scanHexExponentAndSuffix(pos); |
294 scanHexExponentAndSuffix(pos); |
293 } |
295 } |
294 |
296 |
295 private void skipIllegalUnderscores() { |
297 private void skipIllegalUnderscores() { |
296 if (reader.ch == '_') { |
298 if (reader.ch == '_') { |
297 lexError(reader.bp, "illegal.underscore"); |
299 lexError(reader.bp, Errors.IllegalUnderscore); |
298 while (reader.ch == '_') |
300 while (reader.ch == '_') |
299 reader.scanChar(); |
301 reader.scanChar(); |
300 } |
302 } |
301 } |
303 } |
302 |
304 |
327 scanFractionAndSuffix(pos); |
329 scanFractionAndSuffix(pos); |
328 } else { |
330 } else { |
329 if (!seenValidDigit) { |
331 if (!seenValidDigit) { |
330 switch (radix) { |
332 switch (radix) { |
331 case 2: |
333 case 2: |
332 lexError(pos, "invalid.binary.number"); |
334 lexError(pos, Errors.InvalidBinaryNumber); |
333 break; |
335 break; |
334 case 16: |
336 case 16: |
335 lexError(pos, "invalid.hex.number"); |
337 lexError(pos, Errors.InvalidHexNumber); |
336 break; |
338 break; |
337 } |
339 } |
338 } |
340 } |
339 if (reader.ch == 'l' || reader.ch == 'L') { |
341 if (reader.ch == 'l' || reader.ch == 'L') { |
340 reader.scanChar(); |
342 reader.scanChar(); |
502 if (reader.ch == 'x' || reader.ch == 'X') { |
504 if (reader.ch == 'x' || reader.ch == 'X') { |
503 reader.scanChar(); |
505 reader.scanChar(); |
504 skipIllegalUnderscores(); |
506 skipIllegalUnderscores(); |
505 scanNumber(pos, 16); |
507 scanNumber(pos, 16); |
506 } else if (reader.ch == 'b' || reader.ch == 'B') { |
508 } else if (reader.ch == 'b' || reader.ch == 'B') { |
507 if (!allowBinaryLiterals) { |
509 checkSourceLevel(pos, Feature.BINARY_LITERALS); |
508 lexError(pos, "unsupported.binary.lit", source.name); |
|
509 allowBinaryLiterals = true; |
|
510 } |
|
511 reader.scanChar(); |
510 reader.scanChar(); |
512 skipIllegalUnderscores(); |
511 skipIllegalUnderscores(); |
513 scanNumber(pos, 2); |
512 scanNumber(pos, 2); |
514 } else { |
513 } else { |
515 reader.putChar('0'); |
514 reader.putChar('0'); |
598 if (reader.ch == '/') { |
597 if (reader.ch == '/') { |
599 reader.scanChar(); |
598 reader.scanChar(); |
600 comments = addComment(comments, processComment(pos, reader.bp, style)); |
599 comments = addComment(comments, processComment(pos, reader.bp, style)); |
601 break; |
600 break; |
602 } else { |
601 } else { |
603 lexError(pos, "unclosed.comment"); |
602 lexError(pos, Errors.UnclosedComment); |
604 break loop; |
603 break loop; |
605 } |
604 } |
606 } else if (reader.ch == '=') { |
605 } else if (reader.ch == '=') { |
607 tk = TokenKind.SLASHEQ; |
606 tk = TokenKind.SLASHEQ; |
608 reader.scanChar(); |
607 reader.scanChar(); |
611 } |
610 } |
612 break loop; |
611 break loop; |
613 case '\'': |
612 case '\'': |
614 reader.scanChar(); |
613 reader.scanChar(); |
615 if (reader.ch == '\'') { |
614 if (reader.ch == '\'') { |
616 lexError(pos, "empty.char.lit"); |
615 lexError(pos, Errors.EmptyCharLit); |
617 reader.scanChar(); |
616 reader.scanChar(); |
618 } else { |
617 } else { |
619 if (reader.ch == CR || reader.ch == LF) |
618 if (reader.ch == CR || reader.ch == LF) |
620 lexError(pos, "illegal.line.end.in.char.lit"); |
619 lexError(pos, Errors.IllegalLineEndInCharLit); |
621 scanLitChar(pos); |
620 scanLitChar(pos); |
622 if (reader.ch == '\'') { |
621 if (reader.ch == '\'') { |
623 reader.scanChar(); |
622 reader.scanChar(); |
624 tk = TokenKind.CHARLITERAL; |
623 tk = TokenKind.CHARLITERAL; |
625 } else { |
624 } else { |
626 lexError(pos, "unclosed.char.lit"); |
625 lexError(pos, Errors.UnclosedCharLit); |
627 } |
626 } |
628 } |
627 } |
629 break loop; |
628 break loop; |
630 case '\"': |
629 case '\"': |
631 reader.scanChar(); |
630 reader.scanChar(); |
674 } else { |
673 } else { |
675 arg = (32 < reader.ch && reader.ch < 127) ? |
674 arg = (32 < reader.ch && reader.ch < 127) ? |
676 String.format("%s", reader.ch) : |
675 String.format("%s", reader.ch) : |
677 String.format("\\u%04x", (int)reader.ch); |
676 String.format("\\u%04x", (int)reader.ch); |
678 } |
677 } |
679 lexError(pos, "illegal.char", arg); |
678 lexError(pos, Errors.IllegalChar(arg)); |
680 reader.scanChar(); |
679 reader.scanChar(); |
681 } |
680 } |
682 } |
681 } |
683 break loop; |
682 break loop; |
684 } |
683 } |