【编译系统01】编译器 - 词法分析器(lexial)的设计思路
时间:2019/11/29
首先,词法分析器由一个扫描器与状态机组成。
一. 词法分析器整体设计流程
二、设计细节
1. code.txt:
我们假设读取下面文本
2.符号类型的设计
我们使用 enum 数据结构,其好处有两点:
1. 只能选取其成员中的一个。
2. 可以直接用符号的名字命名变量。
- enum symbol {
- KW_MAIN, KW_IF, KW_ELSE, KW_WHILE, KW_INT, KW_COUT, KW_CIN, KW_ENDL, KW_RETURN, // 关键字
- LBRACE, RBRACE, LPAREN, RPAREN, SEMI, COMMA, // 界符
- ASSIGN, ADD, MINUS, TIMES, DIVIDE, // 运算
- EQ, NE, G, GE, B, BE, IN, OUT, // 判断标志位
- STR, NUM, ID, // 字符串,数字,标识符
- END // 文件结尾
- };
3. 扫描器
扫描器会仅仅读取一个字符,先将旧的字符保存,再将读取的字符存储在全局变量ch中,如果读取成功,返回0,否则返回1.
- int getCh() {
- oldch = ch;
- if (fscanf_s(fin, "%c", &ch) == EOF) {
- return ;
- }
- else {
- return ;
- }
- }
4.有限状态机:
其通过当前所读取的字符 ch 来判断其种类。
1)数字:比如如果为 '0',则表示数字,依次"读取-计算-存储"直到不是数字时再退出,将值保存在num中,sym赋值NUM,之后返回。
- else if(ch>='' && ch<='')
- {
- int value = ;
- do {
- value = value * + ch -'';
- f = getCh();
- } while (ch >= '' && ch <= ''); // 判断条件一定要明确
- sym = NUM;
- num = value;
- }
2) ‘=’ 与 ‘==’的区分:当遇到 = 时,超前读取一个字符,来判断。 如果是 == ,在继续读取一个字符(供之后判断使用),否则不用读取。
- case '=':
- f = getCh();
- if (ch == '=') {
- sym = EQ;
- // 再往前读一行
- f = getCh();
- }
- else {
- sym = ASSIGN;
- }
- break;
3) 变量名 与 关键字之前的区分:我们设计了一个数组,当为 变量名或关键字时进行判断。
- /*
- 关键字检索器:将标识符与id区分开来,并打上标记 sym;
- */
- const int arrLen = ;
- const char * keyWords[arrLen] = { "main","if","else","while","int","cout","cin","endl","return" };
- const enum symbol keySymbols[arrLen] = { KW_MAIN, KW_IF, KW_ELSE, KW_WHILE, KW_INT, KW_COUT, KW_CIN, KW_ENDL, KW_RETURN };
- void checkKeyWord() {
- // 将id来遍历 keyWords[] 数组,打上标签
- int flag = ; // 标记是否是关键字
- for (int i = ; i < arrLen; i++) {
- if (strcmp(id, keyWords[i]) == ) {
- sym = keySymbols[i]; // 完成赋值
- flag = ;
- break;
- }
- }
- if (flag == )
- sym = ID;
- }
三、验证检查的可靠性
1. 我们先简单地写了一下测试代码:
- //
- // 测试词法扫描器
- //
- string filename = "C:\\Users\\97905\\source\\repos\\T编译器\\Debug\\abc.txt";
- int ErrorCode = fopen_s(&fin, filename.c_str(), "r");
- if ( == ErrorCode) {
- cout << "打开文件成功" << endl;
- }
- else {
- cout << "错误码: " << ErrorCode << endl;
- return ;
- }
- // 循环解析符号
- getCh(); // 启动时必须先读取第一个字符
- while (getSym()) {
- if (sym == STR) {
- // 输出字符串
- cout << "(string," << str << ")"<< endl;
- }
- else if (sym == NUM) {
- // 输出数字
- cout << "(NUM," << num << ")" << endl;
- }
- else if (sym == ID) {
- cout << "(ID," << id << ")" << endl;
- }
- else {
- cout <<"(关键字或字符," << symbolName[sym] <<")" << endl;
- }
- }
- if (sym == END) {
- cout << "文件读取结束" << endl;
- }
- return ;
2. 将上面那个代码填入进去,最终的测试结果如下。
符合测试要求
四、下一步计划
写一个简单的 "int i;" 与 "i = 3;"的 语法分析程序 与 语义分析程序。
"int i;" 时建立变量记录表
"i = 3;" 时在变量表中查询变量,并且赋值。
这个计划用 MAP 数据结构来实现(毕竟查找比较方便)
预计更新日期:2019/11/30
【编译系统01】编译器 - 词法分析器(lexial)的设计思路的更多相关文章
- (原创)通用查询实现方案(可用于DDD)[附源码] -- 设计思路
[声明] 写作不易,转载请注明出处(http://www.cnblogs.com/wiseant/p/3988592.html). [系列文章] 通用查询实现方案(可用于DDD)[附源码] -- ...
- RBAC角色权限设计思路
1 设计思路 为了设计一套具有较强可扩展性的用户认证管理,需要建立用户.角色和权限等数据库表,并且建立之间的关系,具体实现如下. 1.1 用户 用户仅仅是纯粹的用户,用来记录用户相关信息,如用户名.密 ...
- FPGA Asynchronous FIFO设计思路
FPGA Asynchronous FIFO设计思路 将一个多位宽,且在不停变化的数据从一个时钟域传递到另一个时钟域是比较困难的. 同步FIFO的指针比较好确定,当FIFO counter达到上限值时 ...
- selenium 关键字驱动部分设计思路
1 说明: 1.以下的代码亲测直接可用, 2.设计思路来自博客园的 张飞_ :http://www.cnblogs.com/zhangfei/p/5330994.html / http://w ...
- Sizzle源码分析:一 设计思路
一.前言 DOM选择器(Sizzle)是jQuery框架中非常重要的一部分,在H5还没有流行起来的时候,jQuery为我们提供了一个简洁,方便,高效的DOM操作模式,成为那个时代的经典.虽然现在Vue ...
- 通用查询实现方案(可用于DDD)[附源码] -- 设计思路
原文:通用查询实现方案(可用于DDD)[附源码] -- 设计思路 [声明] 写作不易,转载请注明出处(http://www.cnblogs.com/wiseant/p/3988592.html). ...
- TYPESDK手游聚合SDK服务端设计思路与架构之一:应用场景分析
TYPESDK 服务端设计思路与架构之一:应用场景分析 作为一个渠道SDK统一接入框架,TYPESDK从一开始,所面对的需求场景就是多款游戏,通过一个统一的SDK服务端,能够同时接入几十个甚至几百个各 ...
- 分享一个CQRS/ES架构中基于写文件的EventStore的设计思路
最近打算用C#实现一个基于文件的EventStore. 什么是EventStore 关于什么是EventStore,如果还不清楚的朋友可以去了解下CQRS/Event Sourcing这种架构,我博客 ...
- ENode框架单台机器在处理Command时的设计思路
设计目标 尽量快的处理命令和事件,保证吞吐量: 处理完一个命令后不需要等待命令产生的事件持久化完成就能处理下一个命令,从而保证领域内的业务逻辑处理不依赖于持久化IO,实现真正的in-memory: 保 ...
随机推荐
- http并发访问模型(2)
目录 http并发 并发访问模型 响应流程 从IO的角度看待响应 从函数的角度看待响应 日志处理 我叫张贺,贪财好色.一名合格的LINUX运维工程师,专注于LINUX的学习和研究,曾负责某中型企业的网 ...
- c++ 的namespace及注意事项
前文 下文中的出现的"当前域"为"当前作用域"的简写 namepsace在c++中是用来避免不同模块下相同名字冲突的一种关键字,本文粗略的介绍了一下namesp ...
- Net Core的API文档工具Swagger
一.安装swagger 新建一个net core的api项目,通过NuGet安装Swashbuckle.AspNetCore. 二.注册swagger服务 在Startup.cs中注册Swagger生 ...
- Excel导入导出DataGridView
/// <summary> /// excel表保存到dataTable中 /// </summary> /// <param name="path" ...
- C#-Excel导入工资条群发邮箱
第一次写随笔,一名在实习的程序猿,做的一个小应用,需要的朋友可以参考参考, 使用WinForm实现了一个导入Excel,群发工资条的功能.功能已经实现,还不够完善,. 大致运用了OleDbConnec ...
- Implement Property Value Validation in Code 在代码中实现属性值验证(XPO)
This lesson explains how to set rules for business classes and their properties. These rules are val ...
- 在做nav-bar部分点击路由跳转相同地址时,控制台报错问题。
报错信息: Uncaught (in promise) NavigationDuplicated {_name: "NavigationDuplicated", name: &qu ...
- leaflet 结合 d3.js 实现 geojson 数据地形剖面分析(附源码下载)
前言 leaflet 入门开发系列环境知识点了解: leaflet api文档介绍,详细介绍 leaflet 每个类的函数以及属性等等 leaflet 在线例子 leaflet 插件,leaflet ...
- docker改变默认存储路径到数据盘(自己实践)
一.首先将数据盘格式化分区并挂载(文章中提到的sdb(腾讯云)实践中是vdb(阿里云),文章中挂载在ssd目录下,实践中是挂载到data目录下的,后面安装docker部分以后是实践中的记录,上面数据盘 ...
- Python—创建进程池的方式
创建进程池 from multiprocessing import Pool import time,os result = [] # 存放所有worker函数的返回值 def worker(msg) ...