编译原理-词法分析
Posted 修心_666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编译原理-词法分析相关的知识,希望对你有一定的参考价值。
实验一 词法分析
一、词法分析的任务
词法分析的核心任务是从左到右读入源程序的字符流,识别出一个个的单词。所识别的每一个单词,是下一个有意义的词法元素,如标识符或整数。在识别出下一单词,同时也验证了其词法正确性之后,词法分析程序就会产生一个单词记录,传递给后续阶段使用。
词法分析程序所产生的单词记录通常由两部分信息组成:一个是单词符号(token),对应某个特定意义的词法单元,如标识符、整常数等;另一部分是单词的属性值(attribute)。
程序设计语言中有各种类别的单词,常见的如:
•保留字,也称关键字,如 C 语言中的 if、while、struct、int、typedef 等。
•标识符,用来表示各种名字,如常量名、变量名、函数/过程名、类名等。
•各种类型的常数,如整数 25,浮点数 3.1415,串常数“ABC”等。
•运算符,如 +,,<= 等。
•界符,如逗点,分号,括号等。
例如某语言构词规则 如下:
<无符号整数> ::= <数字> <数字>
<标识符> ::= <字母> <字母><数字>
<字母> ::= a | b | … | X | Y | Z
<数字> ::= 0 1 2 … 8 9
<保留字> ::= constvarprocedurbeginendoddifthencallwhiledoreadwrite
<运算符> ::= + - / = # < <= > >= :=
<界符> ::= ( ) , ;
二、实验内容
对于以下 Decaf 程序片断:
class Main
static void main()
Print(“hello world”);
设计中还要考虑的一点就是对于单词记录中的属性值的处理,比如可能需要将标识符的
名字、类型等信息存放于符号表中。词法分析结果如下:
直接上代码,但是这个代码适用性不高:
#include <iostream>
#include <fstream>
#include <cassert>
#include <string>
#include <vector>
#include <map>
#include <iosfwd>
#include <algorithm>
using namespace std;
//以键值对的形式存储分析结果
vector<pair<string, string>> res;
//语法构词规则
//标识符:用来表示各种名字,如常量名、变量名、函数/过程名、类名等
// 字母+字母|数字
//无符号整数:数字+数字的集合
//字符串常量
//字母
vector<char> chars;
//数字
vector<int> nums = 0,1,2,3,4,5,6,7,8,9 ;
//保留字
vector<string> keywords = "static","void","Print","const","var","procedure","begin","end","odd","if","then","call","while","do","read","write","class" ;
//运算符
vector<string> operators = "+","-","*","/","=","#","<","<=",">",">=",":=" ;
//分隔符
//vector<char> delimiters = '(',')',',',';','','' ;
vector<string> delimiters = "(",")",",",";","","" ;
//初始化字母数组
void Initialize()
char tmp = 'A';
for (int i = 0; i < 26; i++,tmp++)
chars.push_back(tmp);
char t = 'a';
for (int i = 0; i < 26; i++, t++)
chars.push_back(t);
//判断是否是保留字
bool IsKeyword(string tmp,vector<string> keywords)
for (int i = 0; i < keywords.size(); i++)
if (tmp == keywords[i])
return true;
return false;
//判断是否是运算符
bool IsOperator(string tmp)
if (find(operators.begin(), operators.end(), tmp) != operators.end())
return true;
return false;
//判断是否是分隔符
bool IsDelimiter(string tmp)
if (find(delimiters.begin(), delimiters.end(), tmp) != delimiters.end())
return true;
return false;
//判断字符串中是否包含分隔符
bool HaveDelimiter(string tmp)
for (char i : tmp)
string c;
c.push_back(i);
if (find(delimiters.begin(), delimiters.end(), c) != delimiters.end())
return true;
c = "";
return false;
//判断字符串中是否包含""
bool Haveshuang(string tmp)
for (char i : tmp)
if (i == '"')
return true;
return false;
//判断是否是标识符
bool IsIdentifier(string tmp)
if ( find(chars.begin(),chars.end(),tmp[0])!= chars.end() && !IsKeyword(tmp,keywords)
&& !HaveDelimiter(tmp) )
return true;
return false;
//分析单个字符串的属性
void Analyze(string tmp)
if (IsKeyword(tmp, keywords))
res.push_back(pair<string, string>("保留字", tmp));
else if (IsIdentifier(tmp))
res.push_back(pair<string, string>("标识符", tmp));
else if (IsOperator(tmp))
res.push_back(pair<string, string>("运算符", tmp));
else if (IsDelimiter(tmp))
res.push_back(pair<string, string>("分隔符", tmp));
else if (HaveDelimiter(tmp))
//分隔符第一次出现的下标
int index = 0;
for (int i = 0; i < tmp.size(); i++)
string c;
c.push_back(tmp[i]);
if (find(delimiters.begin(), delimiters.end(),c) != delimiters.end())
index = i;
break;
c = "";
//处理分隔前面的字符串
string a = tmp.substr(0, index);
if (IsKeyword(a, keywords))
res.push_back(pair<string, string>("保留字", a));
else if (IsIdentifier(a))
res.push_back(pair<string, string>("标识符", a));
else if (IsOperator(a))
res.push_back(pair<string, string>("运算符", a));
else if (IsDelimiter(a))
res.push_back(pair<string, string>("分隔符", a));
string x;
x.push_back(tmp[index]);
res.push_back(pair<string, string>("分隔符", x));
//找到最后一个分隔符
int lastindex = 0;
for (int i = index; i < tmp.size(); i++)
string b = "";
b.push_back(tmp[i]);
if (IsDelimiter(b))
lastindex = i;
b = "";
if (Haveshuang(tmp))
//处理分隔符()中间的字符串
string c = "";
for (int i = index+1; i < lastindex-1; i++)
c += tmp[i];
res.push_back(pair<string, string>("字符串常量", c));
for (int i = index+1; i < lastindex; i++)
string d;
d.push_back(tmp[i]);
if (IsDelimiter(d))
res.push_back(pair<string, string>("分隔符", d));
d = "";
string y;
y.push_back(tmp[lastindex]);
res.push_back(pair<string, string>("分隔符", y));
//扫描整个字符串 class Main static void main() Print("hello world");
void Saomiao(string buff)
//先计算输入文件流字符串的长度
int bufflength = buff.size();
int spaceindex = 0;
//标志读入字符串常量的状态
bool state = false;
int count = 0;
string tmp = "";
for (int i = 0; i < bufflength; i++)
if (buff[i] == '"')
count++;
state = count % 2;
if (buff[i] != ' ')
tmp += buff[i];
else if (buff[i] == ' ' && state == true)
tmp += buff[i];
else if (buff[i] == ' ' && state == false)
spaceindex = i;
//cout << tmp << endl;
Analyze(tmp);
tmp = "";
int main()
ifstream infile;
infile.open("exp1.txt", ios::in);
if (!infile.is_open())
cout << "打开文件失败" << endl;
return 0;
//第一种方式打开
// char buf[1024] = 0 ;
// while (infile >> buf)
//
// cout << buf << endl;
//
//打开文件 , 将数据存储到buf中
string buff = "";
string tmp = "";
while (getline(infile, tmp))
//cout << buff << endl;
buff += tmp;
//第三种
// string buff;
// char c;
// while ((c = infile.get()) != EOF)
//
// buff += c;
//
// cout << buff << endl;
// class Main static void main() Print("hello world");
Initialize();
Saomiao(buff);
ofstream outFile;
outFile.open("out.txt");//保存的文件名
cout << "分析结果为:" << endl;
for (auto i : res)
outFile << i.first << " " << i.second << endl;
cout << i.first << " " << i.second << endl;
//cout << res.size() << endl;
cout << "结果输出到同目录下的out.txt文件中" << endl;
outFile.close();//关闭文件写入流
infile.close();
return 0;
如果觉得本文对你有帮助的话,不妨关注作者一波,小小的关注其实对我很重要。更多高质量内容与资料请访问:个人主页:修心的小屋
以上是关于编译原理-词法分析的主要内容,如果未能解决你的问题,请参考以下文章