这个对象就包含了已经转换好的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,未来的篇章中我们会用到它们的特殊能力。

相关推荐
mqiqe15 分钟前
线程调度与 Schedulers:Project Reactor 并发模型的核心引擎
java·开发语言·网络
xixiaoyunya1 小时前
JavaScript 异步编程全解析:从回调地狱到 async/await 的演进之路
开发语言·javascript·ecmascript
zjnlswd2 小时前
C#学习笔记4
笔记·学习·c#
精英的英2 小时前
记一次 Qt5 Language Server 开发
开发语言·vscode·qt
烧酒同学2 小时前
【C++】记录size of std::vector的巧妙坑
开发语言·c++·图形渲染
周周哈哈哈2 小时前
线程创建、执行、退出、回收
java·开发语言
gb42152872 小时前
python中Web应用服务器
开发语言·前端·python
曹牧3 小时前
C#:List<string>特定格式输出
windows·c#
萧瑟余晖3 小时前
Java深入解析篇三十六之分布式系统详解
java·开发语言·分布式
ZJU_统一阿萨姆4 小时前
【推理优化进阶】调度器的数学内核:排队论、SLO 与在线决策
开发语言·人工智能·语言模型·系统架构·vllm