赞
踩
上一节所学的主要是语法到语义的内容,通过手动构造语法树来理解编译过程。
在3.5节,书中给出了后缀表达式翻译程序的java实现。根据前面的内容,今天对NC代码编译给出简易的实现。
在实现前,需要几个准备内容用以简化代码:
1. 正则表达式
正则表达式能够对一个字符串进行模式匹配,可以对符合模式的字符串进行检索、替换。
2. 宏
c++中使用宏可以对代码进行批量预处理,对于某些重复的代码可以用宏进行代替。
3. 哈希表
在得到一行代码后,需要对其词法单元进行读入,书中使用的是一个单字符lookahead。这里也使用lookahead,但是每次读入的一个字符串,因为NC代码每个部分都是空格隔开的。
对于每个字符串(即词法单元),都要进行模式判断检查语法是否正确(match),这里需要用到正则表达式,然后用对应的函数进行处理,处理对象过多且代码单一则需要用到宏。
在书中提到,抽象语法树的结点是程序,对应于分析树的非终结符。即是说每个非终结符对应一个函数,用以执行对应的内容。
词法匹配部分如下:
class regs{
map<string, regex> mesh;
smatch m;
string temp;
public:
regs(string file){//从文件读正则表达式
ifstream fin(file);
string str1,str2;
while (!fin.eof()){
fin >> str1 >> str2;
mesh[str1] = regex(str2);
}
}
int match(string pat,string str){//用非终结符pat代表的结构匹配str
temp = str;//必须用temp暂存str 否则会丢失匹配信息
if (mesh.find(pat)!=mesh.end()){
auto pp = mesh[pat];
if (!regex_match(temp, pp))return -1;
regex_search(temp, m, pp);
if (m.size() >= 0){
return m.position();
}
}
return -1;
}
string match_result(){//获取上次匹配的结果(仅限有分组)
return m[1].str();//*!这里需要扩展
}
};
这个类的使用方法是,构造时传入文件名,文件中内容是非终结符和其模式的正则表达式。它以非终结符名作为关键字、正则表达式作为值,构造一个哈希表,用以查询。
翻译器主体如下:
class NCpaser{//手工编写
string cur;
regs pattern;
char code_type;
string lookahead;
public:
NCpaser():pattern("NC\\regs.txt"){//初始化哈希表
;
}
//非终结符列表:stmt id G X Y Z M S T F
void _stmt(){//检验基本语法
if (pattern.match("stmt", cur)>=0){
cur = pattern.match_result();
}
else{
;//报错
}
string temp = cur;
istringstream strin(temp);
while (strin >> lookahead){
#define stmt_pat(s)if (pattern.match(#s, lookahead) >= 0){\
cur = pattern.match_result();\
_##s();\
}
stmt_pat(G)else
stmt_pat(M)else
stmt_pat(X)else
stmt_pat(Y)else
stmt_pat(Z)else
stmt_pat(S)else
stmt_pat(T)else
stmt_pat(F)
}
}
void _N(){
;
}
void _G(){
cout << "执行G指令" << cur << endl;
}
void _M(){
cout << "执行M指令" << cur << endl;
}
void _X(){
cout << "X轴方向" << cur << endl;
}
void _Y(){
cout << "Y轴方向" << cur << endl;
}
void _Z(){
cout << "Z轴方向" << cur << endl;
}
void _S(){
cout << "主轴转速:" << cur << endl;
}
void _T(){
cout << "刀号:" << cur << endl;
}
void _F(){
cout << "进给量:" << cur << endl;
}
void compile(string filename){
ifstream fin(filename);
//预处理,暂空
char buf[512];
;//按行读取
while (fin.getline(buf, 512)){
cur = string(buf);
_stmt();
}
}
};
正则表达式文件regs.txt内容:
stmt N[0-9]+(.*);
N N([0-9]+)
G G([0-9]+)
M M([0-9]+)
T T([0-9]+)
F F([0-9]+)
S S([0-9]+)
X X([+-]?[0-9]+)
Y Y([+-]?[0-9]+)
Z Z([+-]?[0-9]+)
输入code.txt文件内容:
N001 G01 X-100 Y20 Z+35 M03 S40 T50 F40;
N002 G01 X35 Y-29 Z30 M03 S40 T50 F40;
运行结果:
总结:这个简易程序主要给出了简单NC语法的翻译,而且在某种意义上并没有实现上一节构造的语法树,因为这里使用了regex库作为辅助。这里的语义动作是输出显示,相当于直接运行代码。事实上代码必须经过语法检验,像之前一篇文章中提到的(http://blog.csdn.net/u011602557/article/details/66979730),指令间存在互斥性,也没有表现出这个语法。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。