下面看一下nextToken()方法的源码实现。

1、Java中的控制字符

  1. case ' ': // (Spec 3.6)
  2. case '\t': // (Spec 3.6)
  3. case FF: // (Spec 3.6) 换页符 换页字符
  4. do {
  5. scanChar(); // 操作的是bufferpointer指针的值
  6. } while (ch == ' ' || ch == '\t' || ch == FF);
  7. endPos = bufpointer;
  8. processWhiteSpace();
  9. break;
  10. case LF: // (Spec 3.4)
  11. scanChar();
  12. endPos = bufpointer;
  13. processLineTerminator();
  14. break;
  15. case CR: // (Spec 3.4) \r
  16. scanChar();
  17. if (ch == LF) { // \n
  18. scanChar();
  19. }
  20. endPos = bufpointer;
  21. processLineTerminator();
  22. break;

关于 LF CR 参考https://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.4
关于FF 或者\t 等参考https://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.6  

2、Java标识符

有如下规定:

(1)标识符是由字母、数字、下划线、美元($)符号组成的

(2)不能以数字开头

(3)不能是java中的关键字

(4)可以用中文,不会报错,但最好不要用中文

实现代码:

  1. case 'A': case 'B': case 'C': case 'D': case 'E':
  2. case 'F': case 'G': case 'H': case 'I': case 'J':
  3. case 'K': case 'L': case 'M': case 'N': case 'O':
  4. case 'P': case 'Q': case 'R': case 'S': case 'T':
  5. case 'U': case 'V': case 'W': case 'X': case 'Y':
  6. case 'Z':
  7. case 'a': case 'b': case 'c': case 'd': case 'e':
  8. case 'f': case 'g': case 'h': case 'i': case 'j':
  9. case 'k': case 'l': case 'm': case 'n': case 'o':
  10. case 'p': case 'q': case 'r': case 's': case 't':
  11. case 'u': case 'v': case 'w': case 'x': case 'y':
  12. case 'z':
  13. case '$': case '_':
  14. scanIdent();
  15. return;

3、数字的表示

  1. case '0':
  2. scanChar();
  3. if (ch == 'x' || ch == 'X') { // 例如int x = 0x101
  4. scanChar();
  5. skipIllegalUnderscores();
  6. if (ch == '.') {
  7. scanHexFractionAndSuffix(false);
  8. } else if (digit(16) < 0) {
  9. lexError("invalid.hex.number");
  10. } else {
  11. scanNumber(16);
  12. }
  13. } else if (ch == 'b' || ch == 'B') { // 例如int x = 0b101
  14. // java7的新特性二进制字面量
  15. if (!allowBinaryLiterals) {
  16. // source {0} 中不支持二进制文字\n(请使用 -source 7 或更高版本以启用二进制文字)
  17. lexError("unsupported.binary.lit", source.name);
  18. allowBinaryLiterals = true;
  19. }
  20. scanChar();
  21. skipIllegalUnderscores();
  22. if (digit(2) < 0) {
  23. // 二进制数字中必须包含至少一个二进制数
  24. lexError("invalid.binary.number");
  25. } else {
  26. scanNumber(2);
  27. }
  28. } else {
  29. putChar('0');
  30. if (ch == '_') {
  31. int savePos = bufpointer;
  32. do {
  33. scanChar();
  34. } while (ch == '_');
  35. if (digit(10) < 0) {
  36. // 非法下划线
  37. lexError(savePos, "illegal.underscore");
  38. }
  39. }
  40. scanNumber(8);
  41. }
  42. return;
  1. case '1': case '2': case '3': case '4':
  2. case '5': case '6': case '7': case '8': case '9':
  3. scanNumber(10);
  4. return;
  5. case '.':
  6. scanChar();
  7. if ('0' <= ch && ch <= '9') {
  8. putChar('.');
  9. scanFractionAndSuffix();
  10. } else if (ch == '.') {
  11. putChar('.'); putChar('.');
  12. scanChar();
  13. if (ch == '.') {
  14. scanChar();
  15. putChar('.');
  16. token = ELLIPSIS;
  17. } else {
  18. lexError("malformed.fp.lit");
  19. }
  20. } else {
  21. token = DOT;
  22. }
  23. return;

  

4、斜杠

  1. case '/':
  2. scanChar();
  3. if (ch == '/') {
  4. do {
  5. scanCommentChar();
  6. } while (ch != CR && ch != LF && bufpointer < buflen);
  7. if (bufpointer < buflen) {
  8. endPos = bufpointer;
  9. processComment(CommentStyle.LINE);
  10. }
  11. break;
  12. } else if (ch == '*') { // 处理文档注释
  13. scanChar();
  14. CommentStyle style;
  15. if (ch == '*') {
  16. style = CommentStyle.JAVADOC;
  17. scanDocComment();
  18. } else {
  19. style = CommentStyle.BLOCK;
  20. while (bufpointer < buflen) {
  21. if (ch == '*') {
  22. scanChar();
  23. if (ch == '/') break;
  24. } else {
  25. scanCommentChar();
  26. }
  27. }
  28. }
  29. if (ch == '/') {
  30. scanChar();
  31. endPos = bufpointer;
  32. processComment(style);
  33. break;
  34. } else {
  35. lexError("unclosed.comment");
  36. return;
  37. }
  38. } else if (ch == '=') {
  39. name = names.slashequals;
  40. token = SLASHEQ;
  41. scanChar();
  42. } else {
  43. name = names.slash;
  44. token = SLASH;
  45. }
  46. return;

  

5、反斜杠

  1. case '\'':
  2. scanChar();
  3. if (ch == '\'') {
  4. lexError("empty.char.lit");
  5. } else {
  6. if (ch == CR || ch == LF)
  7. lexError(pos, "illegal.line.end.in.char.lit");
  8. scanLitChar();
  9. if (ch == '\'') {
  10. scanChar();
  11. token = CHARLITERAL;
  12. } else {
  13. lexError(pos, "unclosed.char.lit");
  14. }
  15. }
  16. return;

  

6、双引号

  1. case '\"':
  2. scanChar();
  3. while (ch != '\"' && ch != CR && ch != LF && bufpointer < buflen)
  4. scanLitChar();
  5. if (ch == '\"') {
  6. token = STRINGLITERAL;
  7. scanChar();
  8. } else {
  9. lexError(pos, "unclosed.str.lit");
  10. }
  11. return;

  

7、默认处理

在Java中,哪些字符组合成为一个Token是通过调用nextToken方法实现的,每调用一次方法就会构造一个Token,而这些Token必然是com.sun.tools.javac.parser.Token中的任何元素之一。其定义如下:

  1. /** An interface that defines codes for Java source tokens
  2. * returned from lexical analysis.
  3. */
  4. public enum Token implements Formattable {
  5. EOF,
  6. ERROR,
  7. IDENTIFIER, // 如类名、包名、变量名、方法名等
  8. ABSTRACT("abstract"),
  9. ASSERT("assert"),
  10. BOOLEAN("boolean"),
  11. BREAK("break"),
  12. BYTE("byte"),
  13. CASE("case"),
  14. CATCH("catch"),
  15. CHAR("char"),
  16. CLASS("class"),
  17. CONST("const"),
  18. CONTINUE("continue"),
  19. DEFAULT("default"),
  20. DO("do"),
  21. DOUBLE("double"),
  22. ELSE("else"),
  23. ENUM("enum"),
  24. EXTENDS("extends"),
  25. FINAL("final"),
  26. FINALLY("finally"),
  27. FLOAT("float"),
  28. FOR("for"),
  29. GOTO("goto"),
  30. IF("if"),
  31. IMPLEMENTS("implements"),
  32. IMPORT("import"),
  33. INSTANCEOF("instanceof"),
  34. INT("int"),
  35. INTERFACE("interface"),
  36. LONG("long"),
  37. NATIVE("native"),
  38. NEW("new"),
  39. PACKAGE("package"),
  40. PRIVATE("private"),
  41. PROTECTED("protected"),
  42. PUBLIC("public"),
  43. RETURN("return"),
  44. SHORT("short"),
  45. STATIC("static"),
  46. STRICTFP("strictfp"),
  47. SUPER("super"),
  48. SWITCH("switch"),
  49. SYNCHRONIZED("synchronized"),
  50. THIS("this"),
  51. THROW("throw"),
  52. THROWS("throws"),
  53. TRANSIENT("transient"),
  54. TRY("try"),
  55. VOID("void"),
  56. VOLATILE("volatile"),
  57. WHILE("while"),
  58. INTLITERAL,
  59. LONGLITERAL,
  60. FLOATLITERAL,
  61. DOUBLELITERAL,
  62. CHARLITERAL,
  63. STRINGLITERAL,
  64. TRUE("true"),
  65. FALSE("false"),
  66. NULL("null"),
  67. LPAREN("("),
  68. RPAREN(")"),
  69. LBRACE("{"),
  70. RBRACE("}"),
  71. LBRACKET("["),
  72. RBRACKET("]"),
  73. SEMI(";"),
  74. COMMA(","),
  75. DOT("."),
  76. ELLIPSIS("..."),
  77. EQ("="),
  78. GT(">"),
  79. LT("<"),
  80. BANG("!"),
  81. TILDE("~"),
  82. QUES("?"),
  83. COLON(":"),
  84. EQEQ("=="),
  85. LTEQ("<="),
  86. GTEQ(">="),
  87. BANGEQ("!="),
  88. AMPAMP("&&"),
  89. BARBAR("||"),
  90. PLUSPLUS("++"),
  91. SUBSUB("--"),
  92. PLUS("+"),
  93. SUB("-"),
  94. STAR("*"),
  95. SLASH("/"),
  96. AMP("&"),
  97. BAR("|"),
  98. CARET("^"),
  99. PERCENT("%"),
  100. LTLT("<<"),
  101. GTGT(">>"),
  102. GTGTGT(">>>"),
  103. PLUSEQ("+="),
  104. SUBEQ("-="),
  105. STAREQ("*="),
  106. SLASHEQ("/="),
  107. AMPEQ("&="),
  108. BAREQ("|="),
  109. CARETEQ("^="),
  110. PERCENTEQ("%="),
  111. LTLTEQ("<<="),
  112. GTGTEQ(">>="),
  113. GTGTGTEQ(">>>="),
  114. MONKEYS_AT("@"),
  115. CUSTOM;
  116.  
  117. ...
  118. }

  

调用nextToken生成的字符集合都是一个Name对象,所有的Name对象都存储在Name.Table这个内部类中,可以参考另外一篇文章:

javac符号名字的管理

Keyworks会将在Token中所有的元素按照它们的Token.name先转化成Name对象,然后建立Name和Token的对应关系,这个关系保存在Keyworks类的key数组中。

Keywords类定义了如下重要的属性:

  1. /** The names of all tokens.
  2. */
  3. private Name[] tokenName = new Name[values().length];  

初始化时填充tokenName,代码如下:

  1. private void enterKeyword(String s, Token token) {
  2. Name n = names.fromString(s);
  3. tokenName[token.ordinal()] = n;
  4. if (n.getIndex() > maxKey) {
  5. maxKey = n.getIndex();
  6. }
  7. }

则数组的值为:

...

因为有tokenName的枚举常量其ordinal从3开始,到109结束。

然后就可以借助tokenName来完成name到Token的映射了,涉及到的属性如下:

  1. /**
  2. * Keyword array. Maps name indices to Token.
  3. */
  4. private final Token[] key;
  5.  
  6. /** The number of the last entered keyword.
  7. */
  8. private int maxKey = 0;

填充key的属性代码如下:

  1. protected Keywords(Context context) {
  2. // ...
  3. key = new Token[maxKey+1];
  4. for (int i = 0; i <= maxKey; i++) {
  5. key[i] = IDENTIFIER;
  6. }
  7. for (Token t : values()) {
  8. if (t.name != null) {
  9. int oi = t.ordinal();
  10. int ti = tokenName[oi].getIndex();
  11. key[ti] = t;
  12. }
  13. }
  14. }

maxKey值为2905。key中的下标为Name的index值,而值就是Token。其值如下:  

  1. 2630=abstract
  2. 2638=assert
  3. 1195=boolean
  4. 2644=break
  5. 1054=byte
  6. 2649=case
  7. 2653=catch
  8. 1092=char
  9. 63=class
  10. 2658=const
  11. 2663=continue
  12. 56=default
  13. 2671=do
  14. 1173=double
  15. 2673=else
  16. 2677=enum
  17. 2681=extends
  18. 2688=final
  19. 2693=finally
  20. 1153=float
  21. 2700=for
  22. 2703=goto
  23. 2707=if
  24. 2709=implements
  25. 2719=import
  26. 2725=instanceof
  27. 1115=int
  28. 2735=interface
  29. 1135=long
  30. 2744=native
  31. 2750=new
  32. 2753=package
  33. 2760=private
  34. 2767=protected
  35. 2776=public
  36. 2782=return
  37. 1072=short
  38. 2788=static
  39. 2794=strictfp
  40. 51=super
  41. 2802=switch
  42. 2808=synchronized
  43. 47=this
  44. 2820=throw
  45. 2825=throws
  46. 2831=transient
  47. 2840=try
  48. 1219=void
  49. 2843=volatile
  50. 2851=while
  51. 2856=true
  52. 2860=false
  53. 2865=null
  54. 2869=(
  55. 2870=)
  56. 2871={
  57. 2872=}
  58. 2873=[
  59. 2874=]
  60. 45=;
  61. 44=,
  62. 43=.
  63. 2875=...
  64. 2878==
  65. 2598=>
  66. 2597=<
  67. 2574=!
  68. 2569=~
  69. 2879=?
  70. 2880=:
  71. 2603===
  72. 2599=<=
  73. 2601=>=
  74. 2605=!=
  75. 2607=&&
  76. 2609=||
  77. 2570=++
  78. 2572=--
  79. 2568=+
  80. 1=-
  81. 46=*
  82. 0=/
  83. 2587=&
  84. 2588=|
  85. 2589=^
  86. 2586=%
  87. 2590=<<
  88. 2592=>>
  89. 2594=>>>
  90. 2881=+=
  91. 2883=-=
  92. 2885=*=
  93. 3=/=
  94. 2887=&=
  95. 2889=|=
  96. 2891=^=
  97. 2893=%=
  98. 2895=<<=
  99. 2898=>>=
  100. 2901=>>>=
  101. 2905=@

  

  

 

  

Scanner类中的nextToken()方法解读的更多相关文章

  1. Java Scanner类中next()和nextLine()方法的区别

    今天在练习中遇到了调用Scanner类中的nextLine()输入字符串自动跳过的问题,在博客上看了两篇解答,原来是nextLine()误认了前面next()输入时的Enter,但还是想了一会儿才弄清 ...

  2. Java基础之Scanner类中next()与nextLine()方法的区别

    java中使用Scanner类实现数据输入十分简单方便,Scanner类中next()与nextLine()都可以实现字符串String的获取,所以我们会纠结二者之间的区别. 其实next()与nex ...

  3. 12-01 Java Scanner类,Scanner类中的nextLine()产生的换行符问题

    分析理解:Scanner sc = new Scanner(System.in); package cn.itcast_01; /* * Scanner:用于接收键盘录入数据. * * 前面的时候: ...

  4. Java中是否可以调用一个类中的main方法?

    前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...

  5. 重写Object类中的equals方法

    Object是所有类的父亲,这个类有很多方法,我们都可以直接调用,但有些方法并不适合,例如下面的student类 public class Student { //姓名.学号.年纪 private S ...

  6. PHP通过反射方法调用执行类中的私有方法

    PHP 5 具有完整的反射 API,添加了对类.接口.函数.方法和扩展进行反向工程的能力. 下面我们演示一下如何通过反射,来调用执行一个类中的私有方法: <?php //MyClass这个类中包 ...

  7. Java String类中的intern()方法

    今天在看一本书的时候注意到一个String的intern()方法,平常没用过,只是见过这个方法,也没去仔细看过这个方法.所以今天看了一下.个人觉得给String类中加入这个方法可能是为了提升一点点性能 ...

  8. Java线程状态及Thread类中的主要方法

    要想实现多线程,就必须在主线程中创建新的线程对象. 不论什么线程一般具有5种状态,即创建,就绪,执行,堵塞,终止. 创建状态: 在程序中用构造方法创建了一个线程对象后,新的线程对象便处于新建状态,此时 ...

  9. [SignalR]在非Hub继承类中使用脚本方法

    原文:[SignalR]在非Hub继承类中使用脚本方法 新建一个普通类OutHub,里面包含一个脚本方法OutHubTest. 因为大家知道,若能让脚本调用到的话,必须继承Hub,那怎么实现了?通过G ...

随机推荐

  1. 自定义View--滚动View

    实现这么一个效果,一个布局中有一个View,那个View会随着我们手指的拖动而滑动,这种效果该如何实现?   我们第一反应应该是自定义一个DragView类继承View,然后重写onTouchEven ...

  2. 20145233《网络对抗》Exp9 Web安全基础实践

    20145233<网络对抗>Exp9 Web安全基础实践 实验问题思考 SQL注入攻击原理,如何防御? SQL注入攻击就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符 ...

  3. Python学习-10.Python函数定义(二)

    在Python中定义函数的时候,可以使用参数默认值的方式定义函数 例子: def welcome(who,state='is',action='talking'): print(who,state,a ...

  4. Java Web系列:JDBC 基础

    ADO.NET在Java中的对应技术是JDBC,企业库DataAccessApplicationBlock模块在Java中的对应是spring-jdbc模块,EntityFramework在Java中 ...

  5. 修改TFS附件大小的限制

    在TFS服务器使用浏览器上打开如下地址:http://localhost:8080/tfs/<CollectionName>/WorkItemTracking/v1.0/Configura ...

  6. 好看的table样式

    收藏个好看的table样式 <style type="text/css">table.gridtable { font-family: verdana,arial,sa ...

  7. iOS 优秀开源项目

    1. 界面 iCarousel: 用来做图片旋转显示效果(相册). MZTimerLabel:用来制作一个计时并显示时间的 label. MSDynamicsDrawerViewController, ...

  8. c语言第六次作业---结构体&文件

    1.本章学习总结 1.1思维导图 1.2学习体会 这次应该是本学期最后一次博客了,总结一下这个学期的学习,一开始就基础薄弱还一直畏难一直懒惰,不想去解决问题导致后面问题越来越多就觉得学习越来越难,后面 ...

  9. Hibernate 框架学习

    什么是hibernate框架? 1.它是应用在javaee 三层架构中的dao层 它的底层就是JDBC 它对JDBC进行了封装,好处就是不用写jdbc的代码,和sql语句,它是一个开源的轻量级框架,现 ...

  10. [CSS3] 边栏导航动画

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...