《TypeScript图形渲染实战:2D架构设计与实现》 —2.2.10 实现_getNumber方法解析数字类型

举报
华章计算机 发表于 2019/12/11 17:01:51 2019/12/11
【摘要】 本节书摘来自华章计算机《TypeScript图形渲染实战:2D架构设计与实现》 一书中第2章,第2.2.10节,作者是步磊峰。

2.2.10  实现_getNumber方法解析数字类型

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

 

private _getNumber ( token: Doom3Token ) : void {

    let val : number = 0.0 ;

    let isFloat : boolean = false ;                                  // 是不是浮点数

    let scaleValue : number = 0.1 ;                              // 缩放的倍数

       

    //获取当前的字符(当前可能的值是[数字,小数点,负号])

    //目前不支持+3.14类似的表示

    //如果 - 3.14这种情况,由于负号和数字之间有空格,所以目前会解析成[ '-' , 3.14 ]

    这两个Token

    //目前支持例如:[ 3.14 , -3.14 ,  .14  , -.14 , 3.  , -3.  ]的表示

    let c : string = this . _getChar ( ) ;

    //预先判断是不是负数

    let isNegate : boolean = ( c === '-' ) ;                 // 是不是负数

    let consumed : boolean = false ;

    //获得0的ASCII编码,使用了字符串的charCodeAt实列方法

    let ascii0 = "0" . charCodeAt ( 0 ) ;

    // 3.14 -3.14 .13 -.13 3. -3.

    // 只能进来3种类型的字符 :  [ -, ., 数字]

    do {

        // 将当前的字符添加到Token中

        token . addChar ( c ) ;

        // 如果当前的字符是.的话,设置为浮点数类型

        if ( c === '.' ) {

            isFloat = true ;

        } else if ( c !== '-' ) {

            // 十进制从字符到浮点数的转换算法

            // 否则如果不是-符号的话,说明是数字(代码运行到这里已经将点和负号操作符都

            排斥掉了,仅可能是数字)

               

            //这里肯定是数字了,获取当前的数字字符的ASCII编码

            let ascii : number = c . charCodeAt ( 0 ) ;

            //将当前数字的ASCII编码减去0的ASCII编码的算法,其实就是进行字符串-

            数字的类型转换算法

            let vc : number = ( ascii - ascii0 ) ;

            if ( ! isFloat )          // 整数部分算法,10倍递增,因为十进制

                val = 10 * val + vc ;

            else {

                // 小数部分算法

                val = val + scaleValue * vc ;

                //10倍递减

                scaleValue *= 0.1 ;

             }

        } /* else {                        // 运行到这段代码时,当前的变量c肯定为负号

                console.log ( " 运行到此处的只能是 : " + c ) ;

        }*/

       //上面循环中的代码没有读取并处理过字符,之所以使用consumed变量,是为了探测

       下一个字符

        if ( consumed === true )

            this . _getChar ( ) ;

       //获得下一个字符后,才设置consumed为true

        c = this . _peekChar() ;

        consumed = true ;

     //结束条件:数据源解析全部完成,或下一个字符既不是数字也不是小数点(如果是浮点

     数表示的话)

    } while (c . length > 0 && ( this . _isDigit ( c ) || ( ! isFloat && c

    === '.' ) ) ) ;

    //如果是负数,要取反

    if ( isNegate ) {

        val = - val ;

    }

        

    //设置数字值和NUMBER类型

    token.setVal ( val ) ;

}

 

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

 

let input:string = " [ 3.14 , -3.14 ,  .14  , -.14 , 3.  , -3. , +3.14 ] " ;

//使用setSource重新设置数据源

tokenizer . setSource ( input ) ;

while ( tokenizer . getNextToken ( token ) ) {

    if ( token . type === ETokenType . NUMBER ) {

        console . log ( "NUMBER : " + token . getFloat () ) ;

    }

    else {

        console . log( "STRING : " + token . getString ( ) ) ;

    }

}

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

* 左右中括号及逗号作为STRING类型的Token正常地解析出来。

* [3.14 , -3.14 ,  .14  ,-.14 , 3.  ,-3.]表示方式也正常解析出来。

  +3.14这种形式无法正确解析,如果想要支持正号“+”解析操作也不难,毕竟已经完成了负号“-”解析,处理流程类似,这个问题就交给读者尝试解决。

 image.png

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


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。