接下来我们来看一下IDoom3Tokenizer词法解析器中最复杂的一个解析方法,具体代码如下所示:

  1. private _getNumber ( token: Doom3Token ) : void {
  2. let val : number = 0.0 ;
  3. let isFloat : boolean = false ; // 是不是浮点数
  4. let scaleValue : number = 0.1 ; // 缩放的倍数
  5. //获取当前的字符(当前可能的值是[数字,小数点,负号] )
  6. //目前不支持+3.14类似的表示
  7. //如果 - 3.14这种情况,由于负号和数字之间有空格,所以目前会解析成[ '-' , 3.14 ]这两个token
  8. //目前支持例如:[ 3.14 , -3.14 , .14 , -.14 , 3. , -3. ]的表示
  9. let c : string = this . _getChar ( ) ;
  10. //预先判断是不是负数
  11. let isNegate : boolean = ( c === '-' ) ; // 是不是负数
  12. let consumed : boolean = false ;
  13. //获得0的ascii编码,使用了字符串的charCodeAt实列方法
  14. let ascii0 = "0" . charCodeAt ( 0 ) ;
  15. // 3.14 -3.14 .13 -.13 3. -3.
  16. // 只能进来三种类型的字符 : [ - . 数字 ]
  17. do {
  18. // 将当前的字符添加到token中去
  19. token . addChar ( c ) ;
  20. // 如果当前的字符是.的话,设置为浮点数类型
  21. if ( c === '.' ) {
  22. isFloat = true ;
  23. } else if ( c !== '-' ) {
  24. // 10进制从字符到浮点数的转换算法
  25. // 否则如果不是-符号的话,说明是数字(代码运行到这里已经将点和负号操作符都排斥掉了,仅可能是数字)
  26. //这里肯定是数字了,我们获取当前的数字字符的ascii编码
  27. let ascii : number = c . charCodeAt ( 0 ) ;
  28. //将当前数字的ascii编码减去"0"的ascii编码的算法其实就是进行字符串-数字的类型转换算法
  29. let vc : number = ( ascii - ascii0 ) ;
  30. if ( ! isFloat ) // 整数部分算法,10倍递增,因为10进制
  31. val = 10 * val + vc ;
  32. else {
  33. // 小数部分算法
  34. val = val + scaleValue * vc ;
  35. //10倍递减
  36. scaleValue *= 0.1 ;
  37. }
  38. } /* else { // 运行到这段代码时,当前的变量c肯定为负号
  39. console.log ( " 运行到此处的只能是 : " + c ) ;
  40. }*/
  41. //上面循环中的代码没有消费字符,之所以使用consumed变量,是为了探测下一个字符
  42. if ( consumed === true )
  43. this . _getChar ( ) ;
  44. //获得下一个字符后,才设置consumed为true
  45. c = this . _peekChar() ;
  46. consumed = true ;
  47. //结束条件:数据源解析全部完成或下一个字符既不是数字也不是小数点(如果是浮点数表示的话)
  48. } while (c . length > 0 && ( this . _isDigit ( c ) || ( ! isFloat && c === '.' ) ) ) ;
  49. //如果是负数的话,要取反
  50. if ( isNegate ) {
  51. val = - val ;
  52. }
  53. //设置数字值和NUMBER类型
  54. token.setVal ( val ) ;
  55. }

  上面这段代码还是比较复杂的,要理解这段代码,最好的方式就是使用一个具有典型性的例子,我们来看一下如下代码:

  1. et input:string = " [ 3.14 , -3.14 , .14 , -.14 , 3. , -3. , +3.14 ] " ;
  2. //我们使用setSource重新设置数据源
  3. tokenizer . setSource ( input ) ;
  4. while ( tokenizer . getNextToken ( token ) ) {
  5. if ( token . type === ETokenType . NUMBER ) {
  6. console . log ( "NUMBER : " + token . getFloat () ) ;
  7. }
  8. else {
  9. console . log( "STRING : " + token . getString ( ) ) ;
  10. }
  11. }

  运行代码后的结果如图2.3所示:

  • 左右中括号以及逗号作为STRING类型的Token正常的解析出来。
  • [3.14 , -3.14 , .14 , -.14 , 3. , -3.]表示方式也正常解析出来。  +3.14这种形式无法正确解析,如果想要支持正号(+)解析操作,也不难,毕竟我们已经完成了负号(-)解析,处理流程类似,这个问题就交给各位读者去解决。

图2.3 不支持的数字解析格式