先来看一下如何调用Doom3的词法解析器,然后再去了解如何实现过程。首先创建一个名为doom3TokenizerTest . ts的文件,并导入如下四个结构:

  1. import { IDoom3Token , IDoom3Tokenizer , Doom3Factory , ETokenType } from " ./src/doom3Tokenizer" ;

  然后将要解析的字符串赋值给一个string类型的变量,需要注意的是我们使用了ES6中的模板字符串(使用了开单引号xxx,而不是双引号"xxx"或单引号'xxx'的方式来定义字符串字面值):

  1. let str : string = ` // 注意:这是开单引号`,不是单引号'
  2. numMeshes 5
  3. /*
  4. * joints 关键字定义了骨骼动画的 bindPose
  5. */
  6. joints {
  7. "origin" -1 ( 0 0 0 ) ( -0.5 -0.5 -0.5 )
  8. "Body" 0 ( -12.1038131714 0 79.004776001 ) ( -0.5 -0.5 -0.5 ) // origin
  9. }
  10. ` ; // 注意:这是开单引号`,不是单引号'

  最后来看一下如何使用IDoom3Token和IDoom3Tokenizer的属性和方法,具体代码如下:

  1. // 从Doom3Factory工厂创建IDoom3Tokenizer接口
  2. let tokenizer : IDoom3Tokenizer = Doom3Factory . createDoom3Tokenizer ( ) ;
  3. // IDoom3Tokenizer接口创建IDoomToken接口
  4. let token : IDoom3Token = tokenizer . createDoom3Token ( ) ;
  5. //设置IDoom3Tokenizer要解析的数据源
  6. tokenizer . setSource ( str ) ;
  7. // getNextToken函数返回ture,说明没有到达字符串的结尾,仍有token需要解析
  8. // 解析的结果以传引用的方式从参数token传出来
  9. // 如果getNextToken返回false,说明已经到达字符串结尾,则停止循环
  10. while ( tokenizer . getNextToken ( token ) ) {
  11. //如果当前的token的type是Number类型
  12. if ( token . type === ETokenType . NUMBER ) {
  13. console . log ( " NUMBER : " + token . getFloat ( ) ) ; //输出该数字的浮点值
  14. } else if ( token . isString ( "joints" ) ) {
  15. //如果当前token是字符串类型,并且其值为joints,则输出
  16. console . log ( " 开始解析joints数据 " ) ;
  17. }
  18. else { //否则获取当前token的字符串值
  19. console . log( " STRING : " + token . getString ( ) ) ;
  20. }
  21. }

  我们使用F5快捷键启动VS Code的调试器,会看到在浏览器的控制台中输出如图2.1所示的内容。

图2.1 词法解析后Chrome输出结果

  我们会看到每个关键字(例如numMeshes),标识符(例如origin)以及数字(浮点数,整数以及负数)被正确的输出,并且跳过多行注释和单行注释中的内容。代码中对于joints关键字则进行了特殊处理,因此并没有输出。除此之外,还将左右小括号和左右大括号都作为单独一个Token输出到控制台。

  如果我们想重新解析整个字符串,那么我们可以使用IDoom3Tokenizer接口的reset方法,该方法会将当前索引设置到字符串的首位,这样继续循环调用getNextToken就可以重新解析整个字符串。

  我们也可以使用IDoom3Tokenizer的setSource方法重设要解析的字符串(另外一个字符串),setSource方法内部也会将当前索引重置到字符串的首位。