一个礼拜之后我终于从成都回来了, 从今天开始更新会恢复...

一点小的改进

lex()的时候距离我上一次写已经一个礼拜了, 所以我回顾了一下之前的代码, 发现还是有瑕疵. 比如考虑到一个较短的程序, 短到小于BUFFERSIZE(256), 这时其实我的程序是有错的, 因为此时buffer中的内容有一部分是未定义的... 所以为了防止这种情况我又添加了一个变量, 叫做num, 它代表的是目前buffer中实际有效的字符数.

只有几个地方进行了修改, 很简单 :

Lexer(std::ifstream& ifs):ifs(ifs), EndOfFile(false), idx(0), row(1), column(0){
updateBuffer();
lex();
}
    void updateBuffer(){

        // first read...
if(num == 0 && !EndOfFile){
ifs.read(buffer, BUFFERSIZE);
num = ifs.gcount();
if(ifs.eof()){
EndOfFile = true;
}
return;
}
if(idx <= LIMITSIZE || EndOfFile){
return;
} idx -= LIMITSIZE;
strncpy(buffer, buffer + LIMITSIZE, COPYLENGTH);
ifs.read(buffer + COPYLENGTH, LIMITSIZE);
num = COPYLENGTH + ifs.gcount();
if(ifs.eof()){
EndOfFile = true;
}
}
void Lexer::eatSpace(){
char ch = 0;
//change here!!!
while(idx != num && (ch = buffer[idx++])){
updateBuffer();
switch (ch){
case '\n':{
++row;
column = 0;
break;
}
case ' ':{ }
case '\t':{
++column;
break;
}
default:{
--idx;
return;
}
}
}
}
char getNextChar(){
updateBuffer();
++column;
//change here!!!
if(idx == num){
// error.
}
return buffer[idx++];
}

所以改动的地方都已经使用备注标出, 主要思路在于 :

  1. 增加了updateBuffer初始化buffer功能, 所以关于缓冲中有效字符数量(num), 是否达到文件末尾(EndOfFile)等变量的设置都会在这个函数, 也只会这个函数中进行.
  2. 源代码的结束只出现在eatSpace()中和每一次循环的开头, 所以在getNextChar()中出现只有一种情况, 就是源代码有错.

lex()的设计

最后的任务就是设计这个关键的函数lex(), 我个人想到的最清晰易懂的方式就是通过预读然后调用相应的识别函数的方式来进行词法解析.

我们从简单的几个入手 :

void Lexer::lex() {
eatSpace();
char ch;
while(idx != num) {
ch = getNextChar();
switch (ch) {
case '+':
case '-':
case '*':
case '/': {
if (getNextChar() == '=') {
list.pushBack(Token(Token::OPERATOR, ch + "=", row, column));
} else {
backtrace();
list.pushBack(Token(Token::OPERATOR, ch + "", row, column));
}
break;
} case '=':{
if(getNextChar() == ch){
list.pushBack(Token(Token::OPERATOR, ch + ch + "", row, column));
}else{
backtrace();
list.pushBack(Token(Token::OPERATOR, ch + "", row, column));
}
break;
} case '&':
case '|':
case '!':
list.pushBack(Token(Token::OPERATOR, ch + "", row, column));
break; case ';':
list.pushBack(Token(Token::SEMI, ch + "", row, column));
break; case '(':
case ')':
case '{':
case '}':
case '[':
case ']':
list.pushBack(Token(Token::BRACKET, ch + "", row, column));
break; }
eatSpace();
}
}

然后是字符串解析函数 :

std::string Lexer::stringParse() {
char ch;
std::string temp;
bool escape = false;
while(escape || (ch = getNextChar()) != '"'){
if(escape){
switch (ch){
case 'n':
temp += '\n';
break;
case 't':
temp += '\t';
break;
case '"':
temp += '\"';
break;
case '\\':
temp += '\\';
break;
default:
//error
;
}
escape = false;
continue;
} switch (ch){
case '\\':
escape = true;
continue;
default:
temp += ch;
}
}
return temp;
}

此时的lexer() ...

void Lexer::lex() {
eatSpace();
char ch;
while(idx != num) {
ch = getNextChar();
switch (ch) {
case '+':
case '-':
case '*':
case '/': {
if (getNextChar() == '=') {
list.pushBack(Token(Token::OPERATOR, ch + "=", row, column));
} else {
backtrace();
list.pushBack(Token(Token::OPERATOR, ch + "", row, column));
}
break;
} case '=':{
if(getNextChar() == ch){
list.pushBack(Token(Token::OPERATOR, ch + ch + "", row, column));
}else{
backtrace();
list.pushBack(Token(Token::OPERATOR, ch + "", row, column));
}
break;
} case '&':
case '|':
case '!':
list.pushBack(Token(Token::OPERATOR, ch + "", row, column));
break; case ';':
list.pushBack(Token(Token::SEMI, ch + "", row, column));
break; case '(':
case ')':
case '{':
case '}':
case '[':
case ']':
list.pushBack(Token(Token::BRACKET, ch + "", row, column));
break; case '0': {
// int or float
std::string temp("0");
if (getNextChar() == '.') {
temp += '.';
while (isDigit(ch = getNextChar())) {
temp += ch;
}
}
backtrace();
list.pushBack(Token(Token::INT, temp, row, column));
break;
} case '"':
list.pushBack(Token(Token::STRING, stringParse(), row, column)); }
eatSpace();
}
}

由于intfloat有两种情况, 所以这里分开设计, 先讨论了比较简单的0开头的情况.

然后把剩下的一些在switch的default中补齐.

void Lexer::lex() {
eatSpace();
char ch;
while(idx != num) {
ch = getNextChar();
switch (ch) {
case '+':
case '-':
case '*':
case '/': {
if (getNextChar() == '=') {
list.pushBack(Token(Token::OPERATOR, ch + std::string("="), row, column));
} else {
backtrace();
list.pushBack(Token(Token::OPERATOR, ch + std::string(""), row, column));
}
break;
} case '=':{
if(getNextChar() == ch){
list.pushBack(Token(Token::OPERATOR, std::string("") + ch + ch , row, column));
}else{
backtrace();
list.pushBack(Token(Token::OPERATOR, ch + std::string(""), row, column));
}
break;
} case '&':
case '|':
case '!':
list.pushBack(Token(Token::OPERATOR, ch + std::string(""), row, column));
break; case ';':
list.pushBack(Token(Token::SEMI, ch + std::string(""), row, column));
break; case '(':
case ')':
case '{':
case '}':
case '[':
case ']':
list.pushBack(Token(Token::BRACKET, ch + std::string(""), row, column));
break; case '0': {
// int or float
bool isFloat = false;
std::string temp("0");
if (getNextChar() == '.') {
isFloat = true;
temp += '.';
while (isDigit(ch = getNextChar())) {
temp += ch;
}
}
backtrace();
isFloat ? list.pushBack(Token(Token::FLOAT, temp, row, column))
: list.pushBack(Token(Token::INT, temp, row, column));
break;
} case '"':
list.pushBack(Token(Token::STRING, stringParse(), row, column)); default:{
if(isDigit(ch) && ch != 0){
bool isFloat = false;
std::string temp;
temp += ch;
while (isDigit(ch = getNextChar())) {
temp += ch;
}
if (getNextChar() == '.') {
isFloat = true;
temp += '.';
while (isDigit(ch = getNextChar())) {
temp += ch;
}
}
backtrace();
isFloat ? list.pushBack(Token(Token::FLOAT, temp, row, column))
: list.pushBack(Token(Token::INT, temp, row, column));
} else if(isID(ch) && !isDigit(ch)){
std::string temp;
temp += ch;
while (isID(ch = getNextChar())) {
temp += ch;
}
backtrace();
list.pushBack(Token(Token::IDENTIFIER, temp, row, column));
} else{
//error
}
} }
eatSpace();
}
}

然后在进行了简单的测试 :

main.cpp :

#include <iostream>
#include <fstream>
#include "Font/Lexer/Lexer.h" int main() {
std::ifstream ifstream("/Users/zhangzhimin/x.txt");
Lexer lexer(ifstream);
lexer.print();
return 0;
}

x.txt

int main(){
int x = 3;
x += 3.5;
a123b = 4.3333;
"\n1\t2\\\"";
> *= +++ <
return 0;
}

结果如下

int
main
(
)
{
int
x
=
3
x
+=
3
5
a123b
=
4
3333 1 2\"
;
*=
+
+
+
return
0
;
}

除了没有加入报错, 其他的都ok了, 我目前还不太了解C++中的异常机制, 毕竟才学了不到一个月, 其他的以后再说吧, 反正词法分析就告一段落了...

Lexer的设计--下(5)的更多相关文章

  1. Lexer的设计--上(3)

    lexer的构造函数 有了上一节Token做铺垫, 可以开始设计lexer, 首先应该想到的是, 源代码是以文件流的格式传到编译器中的, 所以作为编译器的前段的第一个阶段, lexer必须负责处理输入 ...

  2. 客户端热更新框架之UI热更框架设计(下)

    上一篇笔者介绍了关于什么是热更新,为什么需要热更新的技术文章.本篇就专门针对UI框架的热更新功能实现部分展开讨论,讨论的重点是热更新如何与UI框架进行结合? 现在笔者把设计“UI热更新框架”的整体设计 ...

  3. Java进阶专题(十八) 系统缓存架构设计 (下)

    前言 上章节介绍了Redis相关知识,了解了Redis的高可用,高性能的原因.很多人认为提到缓存,就局限于Redis,其实缓存的应用不仅仅在于Redis的使用,比如还有Nginx缓存,缓存队列等等.这 ...

  4. div+css 设计下拉

    css样式 <style type="text/css"> <!-- /* www.divcss5.com CSS下拉菜单实例 */ * { margin:; p ...

  5. Lexer的设计--中(4)

    设计一个小型的内存池以及链表 上一节撸到万事俱备只欠真正的lex, 但是lex的作用是将源代码转化为Token流, 用什么保存Token? 这就涉及到我们要接触的第一个数据结构-链表, 虽然标准库中很 ...

  6. NoSql数据库使用半年后在设计上面的一些心得

    NoSql数据库这个概念听闻许久了,也陆续看到很多公司和产品都在使用,优缺点似乎都被分析的清清楚楚.但我心里一直存有一个疑惑,它的出现究竟是为了解决什么问题? 这个疑惑非常大,为此我看了很多分析文章, ...

  7. 企业SOA架构设计理论

    SOA简介 SOA(Service-Oriented Architecture,面向服务架构)是一种将信息系统模块化为服务的架构风格.拥有了服务之后,我们就可以迅速地将这些服务按不同方式重新组合,从而 ...

  8. ASP.NET SignalR 高可用设计

    在 One ASP.NET 的架构图中,微软将 WebAPI 和 SignalR 归类到 Services 类型与 MVC.Web Forms 同列为一等公民,未来的 ASP.NET 5 尽管还在be ...

  9. 安卓app设计规范整理和Android APP设计篇(转)

    随着安卓智能手机不停的更新换代.安卓手机系统越来越完美,屏幕尺寸也越来越大啦!比如最近小米的miui 6的发布和魅族手机系统的更新等等. 以小米MIUI6的安卓手机来说,MIUI6进行了全新设计,坚持 ...

随机推荐

  1. Redis tomcat

    http://blog.csdn.net/fu9958/article/details/17325563 http://my.oschina.net/kolbe/blog/618167 http:// ...

  2. oracle汉字占用字节长度

    1.        今天调查一个oracle数据库问题的时候,发如今11g中一个汉字占2个字节,在10g中占3个字节.导致将11g数据库中的数据导入到10g的时候总是出错.開始的时候还以为是11g和1 ...

  3. php面试题12(多态web服务器共享session的方法:将session存到数据库)($val=&$data[$key];)

    php面试题12(多态web服务器共享session的方法:将session存到数据库)($val=&$data[$key];) 一.总结 1.多态web服务器共享session的方法: ...

  4. 忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(8)枚举、补码

    一.枚举 # include <stdio.h> enum WeekDay //定义了一个数据类型(值只能写以下值) { MonDay, TuesDay, WednesDay, Thurs ...

  5. [Angular] Wrap a third party lib into service

  6. [iOS]iOS开发人员账号申请与注冊流程

    郝萌主倾心贡献,尊重作者的劳动成果,请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额任意.重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 游戏官方下 ...

  7. 代码在线执行工具(PHP,Java,C++ 等)

    http://www.it1352.com/Onlinetools 支持几十种语言的在线运行. 缺点:对请求频率限制太严格了,一分钟不到十次吧...可以清理浏览器 Cookie 之后重新访问.必须用示 ...

  8. one hot 编码的实现

    one hot 编码,针对的是类别性属性(categorical),类别型属性可以为特征向量中的任一属性,比如性别(one hot 编码的意义在于,属性之间不具有数值上大小的区别,在对最后结果的影响上 ...

  9. iPad和iPhone开发的异同

    niPad和iPhone开发的异同   niPad简介 n什么是iPad p一款苹果公司于2010年发布的平板电脑 p定位介于苹果的智能手机iPhone和笔记本电脑产品之间 p跟iPhone一样,搭载 ...

  10. 【9309】求Y=X1/3

    Time Limit: 1 second Memory Limit: 2 MB 问题描述 求Y=X1/3次方的值.X由键盘输入(x不等于0,在整型范围内).利用下列迭代公式计算: yn + 1=2/3 ...