先来看一下如何调用Doom3的词法解析器,然后再去了解如何实现过程。首先创建一个名为doom3TokenizerTest . ts的文件,并导入如下四个结构:
import { IDoom3Token , IDoom3Tokenizer , Doom3Factory , ETokenType } from " ./src/doom3Tokenizer" ;
然后将要解析的字符串赋值给一个string类型的变量,需要注意的是我们使用了ES6中的模板字符串(使用了开单引号`xxx`,而不是双引号"xxx"或单引号'xxx'的方式来定义字符串字面值):
let str : string = ` // 注意:这是开单引号`,不是单引号'
numMeshes 5
/*
* joints 关键字定义了骨骼动画的 bindPose
*/
joints {
"origin" -1 ( 0 0 0 ) ( -0.5 -0.5 -0.5 )
"Body" 0 ( -12.1038131714 0 79.004776001 ) ( -0.5 -0.5 -0.5 ) // origin
}
` ; // 注意:这是开单引号`,不是单引号'
最后来看一下如何使用IDoom3Token和IDoom3Tokenizer的属性和方法,具体代码如下:
// 从Doom3Factory工厂创建IDoom3Tokenizer接口
let tokenizer : IDoom3Tokenizer = Doom3Factory . createDoom3Tokenizer ( ) ;
// IDoom3Tokenizer接口创建IDoomToken接口
let token : IDoom3Token = tokenizer . createDoom3Token ( ) ;
//设置IDoom3Tokenizer要解析的数据源
tokenizer . setSource ( str ) ;
// getNextToken函数返回ture,说明没有到达字符串的结尾,仍有token需要解析
// 解析的结果以传引用的方式从参数token传出来
// 如果getNextToken返回false,说明已经到达字符串结尾,则停止循环
while ( tokenizer . getNextToken ( token ) ) {
//如果当前的token的type是Number类型
if ( token . type === ETokenType . NUMBER ) {
console . log ( " NUMBER : " + token . getFloat ( ) ) ; //输出该数字的浮点值
} else if ( token . isString ( "joints" ) ) {
//如果当前token是字符串类型,并且其值为joints,则输出
console . log ( " 开始解析joints数据 " ) ;
}
else { //否则获取当前token的字符串值
console . log( " STRING : " + token . getString ( ) ) ;
}
}
我们使用F5快捷键启动VS Code的调试器,会看到在浏览器的控制台中输出如图2.1所示的内容。
我们会看到每个关键字(例如numMeshes),标识符(例如origin)以及数字(浮点数,整数以及负数)被正确的输出,并且跳过多行注释和单行注释中的内容。代码中对于joints关键字则进行了特殊处理,因此并没有输出。除此之外,还将左右小括号和左右大括号都作为单独一个Token输出到控制台。
如果我们想重新解析整个字符串,那么我们可以使用IDoom3Tokenizer接口的reset方法,该方法会将当前索引设置到字符串的首位,这样继续循环调用getNextToken就可以重新解析整个字符串。
我们也可以使用IDoom3Tokenizer的setSource方法重设要解析的字符串(另外一个字符串),setSource方法内部也会将当前索引重置到字符串的首位。