赞
踩
词法分析器的实现参考了 cppreference翻译阶段
词法分析分为以下两个阶段
为了解决转义字符可能对编译产生的影响,所以先进行一次处理,只保留如下四类字符
0-9
)a-z
),26个大写字母(A-Z
)_ { } [ ] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " '
\n
除此之外的所有符号均视为不合法字符,报错 UNAVALIABLE CHARACTER
。
首先先对三类内部无规则的代码进行处理:
//
开始,由回车符 \n
终止/*
开始,由 */
终止“
开始,由 ”
终止‘
开始, ’
终止其结构较为简单,容易构造一个自动机求解,处理时将单/多行注释用一个空格代替,字符串用一个特殊字符代替,字符用另一个特殊字符代替,然后存入常量区。
但是其中有一个较难操作的地方,即上述四类状态中可能出现转义字符,因此有如下转义字符形式:
\
开始,接下来跟若干位数字\
开始,接下来跟一位其他字符当进入转义字符状态时,按照原来的文本读入并存储,且不会在自动机上进行转移。需要说明的是,因为转义字符只可能在字符或者字符串类型中出现,所以不必对其进行转化,只要按照字符串格式存储下来即可,其具体的含义不由词法分析器进行解析,所以只要在读取到 \
时控制其后一位不会使自动机发生状态转移即可。
构造自动机如图所示:
/
//
/*
/*......*
'
"
为了减少状态,转移字符的吞字符操作单独处理。
方便起见,先在待处理串后方插入一个换行符 \n
,所以到本步骤结束时:
UNMATCHED DELIMITER
;\n
所以不可能停留在1状态。因为上述两种操作可以一起进行,所以通过一趟遍历进行处理:
string filterResource(const string &s){ int u=0,v=0,line=1; string ret="",tmp=""; for(int i=0;i<(int)s.size();++i){ if(s[i]<33&&s[i]>126&&s[i]!='\n'){ showError(0,line);//unavaliable character }else if(s[i]=='`'&&u==0){ showError(0,line);//unavaliable character }else if(s[i]=='\\'){ tmp.push_back(s[i]); if(++i<(int)s.size())tmp.push_back(s[i]); }else{ tmp.push_back(s[i]); char c=s[i]; switch(u){ case 0: if(c=='/')v=1; if(c=='\'')v=5; if(c=='\"')v=6; break; case 1: if(c=='/')v=2; else if(c=='*')v=3; else v=0; break; case 2: if(c=='\n')v=0; break; case 3: if(c=='*')v=4; break; case 4: if(c=='/')v=0; else if(c=='*')v=4; else v=3; break; case 5: if(c=='\'')v=0; break; case 6: if(c=='\"')v=0; break; default: assert(0); } } if(v==0){ if(u>=5){ constZone.push_back(tmp); ret.append(" ` "); for(auto x:tmp)if(x=='\n'){ ++line; ret.push_back('\n'); } }else if(u>1){ ret.append(" "); for(auto x:tmp)if(x=='\n'){ ++line; ret.push_back('\n'); } }else{ ret.append(tmp); for(auto x:tmp)if(x=='\n'){ ++line; } } tmp.clear(); } u=v; } if(u>=5){ showError(1,line);//unmatched quotes }else if(u>0){ ret.append(" "); } return ret; }
#include<iostream> using namespace std; int main(){ string s="2313\nxi`xixi\""; int x=0/5; char c= '\n'; int y = /*just for `test \" \n */ 1; cout<<x+y<<endl; cout<<s/* niu `\n` 12 */<<endl; s.push_back(c); // 牛` cout<<c<<endl;//` }
#include<iostream> using namespace std; int main(){ string s= ` ; int x=0/5; char c= ` ; int y = 1; cout<<x+y<<endl; cout<<s <<endl; s.push_back(c); cout<<c<<endl; }
#include<iostream> using namespace std; int main(){ string s="2313\nxi`xixi\""; int x`=0/5; char c= '\n'; int y = /*just for `test \" \n */ 1; cout<<x+y<<endl; cout<<s/* niu `\n` 12 */<<endl; s.push_back(c); // 牛` cout<<c<<endl;//` }
Unavaliable character
on line: 6
#include<iostream> using namespace std; int main(){ string s="2313\nxi`xixi\""; int x=0/5; char c= '\n'; int y = /*just for `test \" \n */ 1; cout<<x+y<<endl; cout<<s/* niu `\n` 12 */<<endl; s.push_back(c); // 牛` cout<<c<<endl;//` } "
Unmatched
on line: 16
先按照ascii码对所有已有字符进行分类:
digit (48~57)
letter (65~90, 95,97~122)
, 即将下划线 _
视为字母sgn (33~45,47,58~64,91~94,123~126)
dot(46)
str (96)
我们需要识别出如下几种数据:
(_|letter)(_|letter|digit)*
< <= > >= = + - * / ^ .
等() { } [ ]
(digit)+
(digit)*.(digit)+
同理,可以构造一个自动机进行求解。
先对所有上述题及的类型进行编码:
<auto,1>
<break,2>
<case,3>
<char,4>
<const,5>
<continue,6>
<default,7>
<do,8>
<double,9>
<else,10>
<enum,11>
<extern,12>
<
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。