这个对象就包含了已经转换好的DFA和各种词法分析器运转所需要的参数。下一步,我们就可以用ScannerInfo对象创建出Scanner对象,请看下面的代码:
·
Scanner scanner = new Scanner(info); string source = "asdf04a 1107 else"; StringReader sr = new StringReader(source); scanner.SetSource(new SourceReader(sr)); scanner.SetSkipTokens(WHITESPACE.Index); Lexeme l1 = scanner.Read(); Console.WriteLine(l1.TokenIndex); //等于ID.Index Console.WriteLine(l1.Value); //等于 asdf04a Lexeme l2 = scanner.Read(); Console.WriteLine(l2.TokenIndex); //等于NUM.Index Console.WriteLine(l2.Value); //等于 1107 Lexeme l3 = scanner.Read(); Console.WriteLine(l3.TokenIndex); //等于ELSE.Index Console.WriteLine(l3.Value); //等于 else Lexeme l4 = scanner.Read(); Console.WriteLine(l4.TokenIndex); //等于info.EndOfStreamTokenIndex Console.WriteLine(l4.Value); //等于 null |
创建Scanner对象时,需要传入上一步生成的ScannerInfo对象,接下来可以指定输入的源代码。这里我们用StringReader来读取一段字符串源代码。注意Scanner的SetSkipTokens方法,可以设定词法扫描器自动跳过的单词。比如我们不希望词法分析器返回空白字符的词素,就设定跳过WHITESPACE单词。在操作Scanner类的时候,所有与Token相关的操作都是通过Token.Index(一个整数)来完成的,因为Scanner内部仅仅保存了Token在Lexicon内部的索引值,这样可以减小内存使用并且提高效率。
一切准备就绪之后就可以调用scanner.Read()方法来进行词法分析了!每次调用scanner.Read()会返回下一个词素(Lexeme对象),从Lexeme的属性中我们可以拿到该词素对应的单词类型(仍然是以Token.Index整数形式),词素的字符串表示(Value属性)以及词素在源代码中位置等丰富的信息。当扫描到文件或字符串尾部时,scanner.Read()会返回一个特殊的词素表示End Of Stream。这个特殊词素的TokenIndex可以从ScannerInfo对象查询到(每个ScannerInfo的EndOfStreamTokenIndex会不一样)。大家可以试着运行一下上述代码,并且修改自己的词法定义或源代码,来观察Scanner类的各种行为。另外VBF.Compilers.Scanner库还提供了两种具有特殊能力的Scanner——分别是PeekableScanner和ForkableScanner,未来的篇章中我们会用到它们的特殊能力。
更多推荐

所有评论(0)