词法分析步骤是编译器处理的第一步,目的是将用户输入的符号流转化为 后面语法分析所需的 词法单元的形式.
一般来说,经过了词法分析之后, 所有的输入内容都将变成"编译器可识别"的形式. 词法单元主要分为几类, 比如标示符,常量,标点符号,操作符,关键字等等. 对于常量和标示符而言,词法分析的结果还应该包含它所带有的实际含义和值.
词法分析的作用: 1.剔除空格 换行符 制表符等等,
2.通过换行符记录数据的行数,以便在返回错误的时候定位到错误行.
词法分析的实现有很多方式,这里我们采用栈的数据结构对其词法分析过程进行模拟.
先贴出我们实验课的词法内容吧.
(1)待分析的简单语言的词法
1) 关键字
begin if then while do end
2) 运算符和界符
:= + - * / < <= > >= <> = ; ( ) #
3) 其他单词是标识符(ID)和整形常数(NUM),通过以下正规式定义:
ID=letter(letter|digit)*
NUM=digitdigit*
4) 空格由空白、制表符和换行符组成。空格一般用来分隔ID、NUM、运算符、界符和关键字,词法分析阶段通常被忽略。
4) 空格由空白、制表符和换行符组成。空格一般用来分隔ID、NUM、运算符、界符和关键字,词法分析阶段通常被忽略。
(2)各种单词符号对应的种别编码
单词符号 | 种别码 | 单词符号 | 种别码 |
begin | 1 | : | 17 |
if | 2 | := | 18 |
then | 3 | < | 20 |
while | 4 | <> | 21 |
do | 5 | <= | 22 |
end | 6 | > | 23 |
letter(letter|digit)* | 10 | >= | 24 |
digitdigit* | 11 | = | 25 |
+ | 13 | ; | 26 |
- | 14 | ( | 27 |
* | 15 | ) | 28 |
/ | 16 | # | 0 |
(3)词法分析程序的功能
输入:所给文法的源程序字符串
输出:二元组(syn, token或sum)构成的序列。
syn为单词种别码;
token为存放的单词自身字符串;
sum为整形常数。
例如:对源程序begin x:=9;if x>0 then x:=2*x+1/3;end# 经词法分析后输出如下序列:(1,begin)(10,’x’) (18,:=) (11,9) (26,;) (2,if)……
实验的内容并不复杂,用到的数据结构和类型也很简单,没有什么复杂的算法,慢慢写就可以了.
后面就是代码了,也许会有些小bug,因为后面改的时候不记得是否保存了.....不过应该不是大问题..大家参考就好.
#include "define.h"
int _isLetter(char exp) //判断字母
{
if(exp >='A'&&exp<='Z'||exp>='a'&&exp<='z')
return 1;
return 0;
};
bool _isKey(string s) //判断关键字
{
if(Keylist->Key_search(s))
return true;
return false;
};
bool _isOpe(char c) //判断操作符
{
if(Opelist->Ope_search(c))
return true;
return false;
};
int _isDigit(char exp) //判断数字
{
if(exp >='0'&&exp <='9')
return 1;
return 0;
};
int NO(char c) //返回键值
{
if(c=='+')return 13;
if(c=='-')return 14;
if(c=='*')return 15;
if(c=='/')return 16;
if(c=='>')return 20;
if(c=='<')return 23;
if(c=='=')return 25;
if(c==':')return 17;
if(c==';')return 26;
if(c=='#')return 0;
if(c==')')return 28;
if(c=='(')return 27;
};
int NO(char c1,char c2)
{
if(c1=='<'&&c2=='>')return 21;
if(c1==':'&&c2=='=')return 18;
if(c1=='<'&&c2=='=')return 22;
if(c1=='>'&&c2=='=')return 24;
};
void print() //打印函数,也是处理栈,
{
int sz;
int n[MAX_LENGTH];char str[MAX_LENGTH] ={' '};char o[MAX_LENGTH] = {' '};
if(!cs.empty())
{
sz = cs.size();
for(int i=sz-1;i>-1;i--)
{ str[i]=cs.top();cs.pop();}
if(_isKey(str));
else {cout<<"("<<10<<",";
for(int j=0;j<sz;j++)
cout<<str[j];cout<<")"<<endl;}
}
else if(!ns.empty())
{
sz = ns.size();
for(int i=sz-1;i>-1;i--)
{
n[i]=ns.top();
ns.pop();
}
cout<<"("<<11<<",";
for(int j=0;j<sz;j++)
cout<<n[j]-48;
cout<<")"<<endl;
}
};
ostream& operator << (ostream& out,char* st)
{
int i=0;
while(i<sizeof(st))
{out<<st[i];i++;}
return out;
};
void analysis(const char* filename) //词法分析的主体,遇到其他符号的时候就跳到栈的处理,完成匹配.
{
filein.open(filename,ios::in);
if(!filein)
{
cout<<"File open error!\n";
return ;
}
char c;
while((c = filein.get())!=EOF)
{
if(_isOpe(c))
{
if(!os.empty())
{
cout<<"("<<NO(os.top(),c)<<";"<<os.top()<<c<<")"<<endl;
os.pop();
}
else os.push(c);
print(); //跳
}
if(_isLetter(c)==1)
{
cs.push(c);
if(!os.empty())
{
cout<<"("<<NO(os.top())<<";"<<os.top()<<")"<<endl;
os.pop();
}
}
else if(_isDigit(c)==1&&!cs.empty())
{
cs.push(c);
if(!os.empty())
{
cout<<"("<<NO(os.top())<<";"<<os.top()<<")"<<endl;
os.pop();
}
}
else if(_isDigit(c)==1)
{
ns.push(c);
if(!os.empty())
{
cout<<"("<<NO(os.top())<<";"<<os.top()<<")"<<endl;
os.pop();
}
}
else if(c=='\t'||c==' '||c=='\n')
{
if(!os.empty())
{
cout<<"("<<NO(os.top())<<";"<<os.top()<<")"<<endl;
os.pop();
}
print(); //跳
}
}
filein.close();
};
上面就是词法分析的核心部分了.也不是很难,细节部分的处理注意一下就好了.
本系列博客的目的其实就是让后面需要的人有个例子对比而已,有发现bug的可以提出来.
最后如果有需要全部代码的可以私信我,在线必回~~
下一次就是自顶向下的语法分析程序了,期待吧~