标准纯C++实现简单的词法分析器(一)
2006-03-29 09:56
801 查看
一、思路:
使用容器vector<string> 来缓冲文件内容,以便增加效率,以前的总是用getline(FILE*, ...) 或者别的,总之,都要从磁盘不断读取,不断操作,效率肯定不高。 这个思路主要是受到《C++ Primer》3 的影响,其中有个文本操作,采用这种方式。
从文件中具体分离出一个个字符,当然也就简单的多了。
然后再使用状态机,来实现 标识符提取, 这种方式的优点是可以很容易的根据你的需要来扩充或者修改。而且清晰明了哦。
二、实现(部分):
1使用标准的纯C++实现, 估计可以在 Unix 上兼容。不过没有测试;一下是包含头文件:
#include <fstream>
#include <vector>
#include <string>
#include <iostream>
没有任何 linux 或者 windows 等操作系统特有的东西。
2 tokenizer 类定义。 主要实现从文件中提取单个的字符。
/**: class Tokenizer
* 将源文件直接读入到std::vector<stirng> lines_of_source
* 中,来增加操作上的时间效率,代价是空间!
* 重要接口 char getNextChar() & void unGetNextChar()
* 分别从源文件中提取 return lines_of_source[lineno_-1][linepos++];
* 出一个字符 & 退回一个字符。
*/
class Tokenizer {
public:
Tokenizer(const std::string& filename); // use filename.c_str()
virtual ~Tokenizer();
char getNextChar(); // ...primary interface to scanner...
void unGetNextChar();
bool is_good() const { return is_good_; } // very importent
std::vector<std::string>::size_type lineno() const // line start with 1
{ return lineno_; }
protected:
// interface of insert the trace source messages;
void insert_list(const std::string& msg);
void insert_list(const char* msg); //主要是用来保存词法分析产生的文件。
// read and store file to vector<string>,
void read_file(const char* filename);
void store_file(ifstream& is);
// 没有找出一个好的方案来解决 "..." 型的参数,
// 只能用借用msg_temp[]来调用 sprintf 了
char msg_temp[512];
string source_name; // record the source file name;
std::vector<std::string> list_msg_; // trace source
bool is_good_; // 帮助测试是否能够正常工作!
private:
// source file
std::vector<std::string> lines_of_source;
std::vector<std::string>::size_type lineno_; // record source file line no
int bufsize; // record a line size
int linepos; // current line position
};
其中借助很多 《编译原理及实践》这本书的思想和方法。其中很多东西都是可以不要的,当然
我是为了能够产生一个排版清晰的list文件而加如的。
3 tokenizer 类实现(部分):
以下两部分将文件读入,并且存储在 lines_of_source中。
/**: read_file & store_file
* author: lonelyforest;
* data: 2006.03.16
*/
//-----------------------------------------------------------------------------
void Tokenizer::read_file(const char *filename)
{
ifstream infile(filename);
if ( !infile )
{
is_good_ = false;
string errMsg = "Open source file fail! ";
errMsg += filename;
outputMsg(-1, errMsg.c_str());
outputMsg(-1, "Compile must be stop, and check the file wether exists!");
insert_list(errMsg);
insert_list("/nCompile must be stop, and check the file wether exists!/n");
}
else
{
store_file(infile);
}
}
void Tokenizer::store_file(ifstream &is)
{
string linetext;
while(getline(is, linetext ))
{
linetext += "/n";
lines_of_source.push_back(linetext);
}
}
以下是两个主要接口函数的实现:
行标号是从1开始的,以免用户不理解。
char Tokenizer::getNextChar()
{
if ( !(linepos < bufsize ))
{
++lineno_; // now, lineno_ start with 1 !!
if ( lineno_ > lines_of_source.size())
{
return EOF;
}
linepos = 0;
bufsize = lines_of_source[lineno_ -1].length();
if ( EchoSource )
{ // 用于在 list 文件中记录源文件
sprintf(msg_temp, "%4d: %s", lineno_, lines_of_source[lineno_-1].c_str());
insert_list(msg_temp);
}
}
return lines_of_source[lineno_-1][linepos++];
}
// 退回一个字符。
void Tokenizer::unGetNextChar()
{
linepos--;
}
主要标识符分析实现部分待续 ......
使用容器vector<string> 来缓冲文件内容,以便增加效率,以前的总是用getline(FILE*, ...) 或者别的,总之,都要从磁盘不断读取,不断操作,效率肯定不高。 这个思路主要是受到《C++ Primer》3 的影响,其中有个文本操作,采用这种方式。
从文件中具体分离出一个个字符,当然也就简单的多了。
然后再使用状态机,来实现 标识符提取, 这种方式的优点是可以很容易的根据你的需要来扩充或者修改。而且清晰明了哦。
二、实现(部分):
1使用标准的纯C++实现, 估计可以在 Unix 上兼容。不过没有测试;一下是包含头文件:
#include <fstream>
#include <vector>
#include <string>
#include <iostream>
没有任何 linux 或者 windows 等操作系统特有的东西。
2 tokenizer 类定义。 主要实现从文件中提取单个的字符。
/**: class Tokenizer
* 将源文件直接读入到std::vector<stirng> lines_of_source
* 中,来增加操作上的时间效率,代价是空间!
* 重要接口 char getNextChar() & void unGetNextChar()
* 分别从源文件中提取 return lines_of_source[lineno_-1][linepos++];
* 出一个字符 & 退回一个字符。
*/
class Tokenizer {
public:
Tokenizer(const std::string& filename); // use filename.c_str()
virtual ~Tokenizer();
char getNextChar(); // ...primary interface to scanner...
void unGetNextChar();
bool is_good() const { return is_good_; } // very importent
std::vector<std::string>::size_type lineno() const // line start with 1
{ return lineno_; }
protected:
// interface of insert the trace source messages;
void insert_list(const std::string& msg);
void insert_list(const char* msg); //主要是用来保存词法分析产生的文件。
// read and store file to vector<string>,
void read_file(const char* filename);
void store_file(ifstream& is);
// 没有找出一个好的方案来解决 "..." 型的参数,
// 只能用借用msg_temp[]来调用 sprintf 了
char msg_temp[512];
string source_name; // record the source file name;
std::vector<std::string> list_msg_; // trace source
bool is_good_; // 帮助测试是否能够正常工作!
private:
// source file
std::vector<std::string> lines_of_source;
std::vector<std::string>::size_type lineno_; // record source file line no
int bufsize; // record a line size
int linepos; // current line position
};
其中借助很多 《编译原理及实践》这本书的思想和方法。其中很多东西都是可以不要的,当然
我是为了能够产生一个排版清晰的list文件而加如的。
3 tokenizer 类实现(部分):
以下两部分将文件读入,并且存储在 lines_of_source中。
/**: read_file & store_file
* author: lonelyforest;
* data: 2006.03.16
*/
//-----------------------------------------------------------------------------
void Tokenizer::read_file(const char *filename)
{
ifstream infile(filename);
if ( !infile )
{
is_good_ = false;
string errMsg = "Open source file fail! ";
errMsg += filename;
outputMsg(-1, errMsg.c_str());
outputMsg(-1, "Compile must be stop, and check the file wether exists!");
insert_list(errMsg);
insert_list("/nCompile must be stop, and check the file wether exists!/n");
}
else
{
store_file(infile);
}
}
void Tokenizer::store_file(ifstream &is)
{
string linetext;
while(getline(is, linetext ))
{
linetext += "/n";
lines_of_source.push_back(linetext);
}
}
以下是两个主要接口函数的实现:
行标号是从1开始的,以免用户不理解。
char Tokenizer::getNextChar()
{
if ( !(linepos < bufsize ))
{
++lineno_; // now, lineno_ start with 1 !!
if ( lineno_ > lines_of_source.size())
{
return EOF;
}
linepos = 0;
bufsize = lines_of_source[lineno_ -1].length();
if ( EchoSource )
{ // 用于在 list 文件中记录源文件
sprintf(msg_temp, "%4d: %s", lineno_, lines_of_source[lineno_-1].c_str());
insert_list(msg_temp);
}
}
return lines_of_source[lineno_-1][linepos++];
}
// 退回一个字符。
void Tokenizer::unGetNextChar()
{
linepos--;
}
主要标识符分析实现部分待续 ......
相关文章推荐
- 标准纯C++实现简单的词法分析器(二)
- 标准纯C++实现简单的词法分析器(三)
- 标准纯C++实现简单的词法分析器(三)
- 标准纯C++实现简单的词法分析器(一)
- 标准纯C++实现简单的词法分析器(二)
- c++ 简单词法分析器的实现
- C++标准 bind函数用法与C#简单实现
- Windows Phone 8 学习志(探索问题一:如何简单利用Windows Phone Runtime Component项目类型实现C#和C++交互)
- C++实现简单的HTTP客户端(阻塞方式)
- c++ 栈,队列,循环队列 简单实现
- c++简单实现string类
- 简单的学生信息处理程序实现 (Coursera 程序设计与算法 专项课程3 C++程序设计 郭炜、刘家瑛;OpenJudge)
- 一、(2)C++ 实现简单的线性表(链式存储结构 - 单链表)
- 利用 c++模板 类型 推导思想,实现最简单的 判断两个类型 是否一样的 方法
- C++晋升之std中vector的实现原理(标准模板动态库中矢量的实现原理)
- 一个简单的游戏引擎核心状态机的C++实现
- C++简单实现hash table
- C++对象动态生成(Dynamic Create)的简单实现
- C++简单实现GC和内存池
- C++对象动态生成(Dynamic Create)的简单实现