编译原理课内实验报告(词法分析、简单赋值语句的语法分析)

这是笔者在whut选修的编译原理课程的课内实验(含实验报告)
实验内容包含:
(1)词法分析
(2)简单赋值语句的语法分析
温馨提示:本篇博客中的语法Syntax错误拼写成了Synax,请见谅!!

本次博客目录

  • 一、实验要求
  • 二、运行截图展示
  • 三、代码说明
  • 四、词法分析源程序
  • 五、语法分析源程序
  • 六、实验报告免费下载
  • 七、Last but not least

一、实验要求

(1) 完成对C++语言的各类单词的词法分析程序设计。
实际实验时完成了对以下几种单词的分析:
1) 标识符(以字母或下划线开头的连续字符序列)
2)无符号数(包含小数)
3)关键字(如int ,include等)
4)界符(如 ; , 等)
5)运算符(包含复合运算符++,+=等)

(2)对于常用高级语言(如Java、C++语言)的赋值语句用所学过的语法分析方法进行语法分析。
本次实验简化了赋值语句的文法,简化后的文法如下:
文法:
1)<赋值语句>∷= 〈标识符〉 = 〈表达式〉
2) <表达式> ::= <项> <运算符> <项> | <项>
3) <项>::=<因子> <运算符> <因子> |<因子>
4)〈因子〉∷= 〈标志符〉|〈无符号整数〉|(〈表达式〉)
5)〈无符号整数〉∷= 〈数字〉|〈无符号整数〉〈数字〉
6)〈标识符〉∷= 〈字母〉|〈标识符〉〈字母〉|〈标识符〉〈数字〉
7)〈加法运算符〉∷= +|-
8)〈乘法运算符〉∷= *|/

二、运行截图展示

1.词法分析
本次实验从文件input_CStytle.txt文件中读取源程序,经过词法分析后的得到的结果以二元式的形式 <单词类型,单词值>。
其中单词类型包括:关键字keyword,界符boundary,运算符operator,数字digit,标识符token;单词值特殊说明:空格space,水平制表符tab,换行enter。
在这里插入图片描述
在这里插入图片描述
(2)语法分析
1)识别的赋值语句正确:variable_name+=str+cha4;
在这里插入图片描述
2)没有赋值符号的情况:variable_name+str+cha
4;
在这里插入图片描述

三、代码说明

1.项目结构
在这里插入图片描述
2.文件说明
ApplicationEntrance:程序入口
Controller:词法分析总控程序
Analysis:词法分析子程序
SynaxAnalysis:语法分析子程序(递归下降法)
OutputAction:输出相关操作
InputAction:输入相关操作
Constants:常量文件

3.输入文件等
在这里插入图片描述
boundary_CStytle:界符文件
keywords_CStytle:关键字文件
operator_CStytle:操作符文件
input_CStytle:源程序输入文件
output_CStytle:输出文件
input_sentence:语法分析的赋值语句文件

上述文本文件可以根据自身需求自行定义

四、词法分析源程序

ApplicationEntrance:

/*
* @author W-nut
* FileInfo:应用程序入口
*/#include 
#include "Controller.h"
#include "SynaxAnalysis.h"
#include "InputAction.h"
#include "OutputAction.h"
using namespace std;int main()
{//词法分析InputCode();//输入源程序InputKOB();//输入关键字、运算符、界符cout << "这是C语言的词法分析程序!" << endl;Controller();OuptutWord();OutputWordToFile();//语法分析code_vector.clear();word_vector.clear();InputSentence();Controller();OuptutWord();SynaxAnalysis();return 0;
}

Controller:

/** @authot W-nut* FileInfo:词法分析总控程序*/#include 
#include "Analysis.h"
#include "Constants.h"using namespace std;//分析当前字符属于哪一类
int Distribute(const char ch);
bool IsOpreator(const string word);//函数说明:总控程序
void Controller()
{for (int begin=0;begin<code_vector.size();){string word="";int end = begin + 1;int type = Distribute(code_vector[begin]);word += code_vector[begin];if (type == LETTER){for (; end < code_vector.size(); ++end){if (Distribute(code_vector[end]) != BOUNDARY && Distribute(code_vector[end]) != OPERATOR){word += code_vector[end];}else{break;}}LetterAnalysis(word);//标识符或关键字}else if (type == DIGIT){for (; end < code_vector.size(); ++end){//bool sign = true;if (Distribute(code_vector[end]) == DIGIT){word += code_vector[end];}else if (code_vector[end] == '.')//else if (code_vector[end] == '.' && sign) {word += code_vector[end];//!sign;}else{break;}}DigitAnalysis(word);//无符号数}else if (type == BOUNDARY){BoundaryAnalysis(word);}else{for (; end < code_vector.size(); ++end){if (Distribute(code_vector[end]) != DIGIT && Distribute(code_vector[end]) != LETTER && Distribute(code_vector[end]) != BOUNDARY){if (code_vector[end] != '=')word += code_vector[end];else{word += code_vector[end];if (IsOpreator(word)){++end;break;}else{word = word.substr(0, word.length() - 1);break;}}					}else{break;}	}OperatorAnalysis(word);}begin = end;}
}//分析当前字符属于哪一类
int Distribute(const char ch)
{char c_tmp[] = { ch,'\0' };string ch_tmp = c_tmp;//判断是否是字母if ((ch >= 'a' && ch <='z') || (ch >= 'A' && ch <= 'Z')||ch=='_')return LETTER;//判断是否为数字if (ch >= '0' && ch <= '9')return DIGIT;//判断是否为运算符for (const string str : operator_vector){if (str == ch_tmp)return OPERATOR;}//判断是否为界符for (const string str : boundary_vector){if (str == ch_tmp)return BOUNDARY;}
}//判断当前字符串是否是运算符
bool IsOpreator(const string word)
{for (const string str : operator_vector){if (str == word)return true;}return false;
}

Analysis:

/** @authot W-nut* FileInfo:分析子程序*/#pragma once
#include 
#include 
#include "Constants.h"//分析数字
void DigitAnalysis(const string word)
{Word new_word;new_word.word_type = "digit";new_word.word_value = word;word_vector.push_back(new_word);return;
}//分析运算符
void OperatorAnalysis(const string word)
{//判断是否为运算符for (string str : operator_vector){if (str == word){Word new_word;new_word.word_type = "operator";new_word.word_value = word;word_vector.push_back(new_word);return;}}
}//分析界符
void BoundaryAnalysis(const string word)
{Word new_word;new_word.word_type = "boundary";if (word == "\n")new_word.word_value = "enter";else if (word == " ")new_word.word_value = "space";else if (word == "\t")new_word.word_value = "tab";elsenew_word.word_value = word;word_vector.push_back(new_word);return;
}//分析关键字或标识符
void LetterAnalysis(const string word)
{//判断是否为关键字for (string str : keywords_vector){if (str == word){Word new_word;new_word.word_type = "keyword";new_word.word_value = word;word_vector.push_back(new_word);return;}}//以字母开头的不是关键字,就是标识符Word new_word;new_word.word_type = "token";new_word.word_value = word;word_vector.push_back(new_word);return;
}

InputAction:

/** @authot W-nut* FileInfo:输入相关操作*/#pragma once#include 
#include 
#include 
#include "Constants.h"
#include "OutputAction.h"using namespace std;//从文件中读取C语言源代码
void InputCode()
{ifstream inputFile;inputFile.open(INPUT_CSTYTLE, ios::in);if (!inputFile)cout << "文件打开失败" << endl;while (!inputFile.eof()){char p = inputFile.get();code_vector.push_back(p);}inputFile.close();code_vector.pop_back();//弹出文件结束标识//OutputCode();}//从文件读取简单赋值语句
void InputSentence()
{ifstream inputFile;inputFile.open(INPUT_SENTENCE, ios::in);if (!inputFile)cout << "文件打开失败" << endl;while (!inputFile.eof()){char p = inputFile.get();code_vector.push_back(p);}inputFile.close();code_vector.pop_back();//弹出文件结束标识
}//从文件中读取关键字、运算符、界限符
void InputKOB()
{ifstream keyFile;keyFile.open(KEYWORDS_CSTYTLE, ios::in);if (!keyFile)cout << "文件打开失败" << endl;	while (!keyFile.eof()){string str;keyFile >> str;keywords_vector.push_back(str);}keyFile.close();ifstream operatorFile;operatorFile.open(OPERATOR_CSTYTLE, ios::in);if (!operatorFile)cout << "文件打开失败" << endl;while (!operatorFile.eof()){string str;operatorFile >> str;operator_vector.push_back(str);}operatorFile.close();ifstream boundaryFile;boundaryFile.open(BOUNDARY_CSTYTLE, ios::in);if (!boundaryFile)cout << "文件打开失败" << endl;while (!boundaryFile.eof()){char c = boundaryFile.get();string str;str += c;boundary_vector.push_back(str);}boundaryFile.close();boundary_vector.pop_back();//OutputKOB();
}

OutputAction:

/** @authot W-nut* FileInfo:输出相关操作*/#pragma once
#include 
#include "Constants.h"using namespace std;//输出读入的C语言源代码
void OutputCode()
{cout << "读入的源代码如下:" << endl;for (char c : code_vector)cout << c ;cout << endl;cout << "总共读入" << code_vector.size() << "个字符" << endl;
}//输出读入的关键字、运算符、界符
void OutputKOB()
{cout << "读入的关键字如下:" << endl;for (string str : keywords_vector)cout << str << " ";cout << endl;cout << "总共读入" << keywords_vector.size() << "个关键字" << endl;cout << "读入的运算符如下:" << endl;for (string str : operator_vector)cout << str << " ";cout << endl;cout << "总共读入" << operator_vector.size() << "个运算符" << endl;cout << "读入的界符如下:" << endl;for (string str : boundary_vector)cout << str << " ";cout << endl;cout << "总共读入" << boundary_vector.size() << "个界符" << endl;
}//输出二元式到控制台
void OuptutWord()
{cout << "分析后的单词二元式为:" << endl;for (Word word : word_vector){cout << "<" << word.word_type << "," << word.word_value << ">" << endl;}
}//输出二元式到文件
void OutputWordToFile()
{ofstream outputFile;outputFile.open(OUTPUT_CSTYTLE, ios::out );if (!outputFile)cout << "文件打开失败!" << endl;for (const Word word : word_vector){outputFile << "<"<<word.word_type << " , " << word.word_value<<">"<<'\n';}outputFile.close();
}

Constants:

/** @authot W-nut* FileInfo:全局变量、常量文件*/#pragma once#include 
#include 
using namespace std;//the paths of files
const string INPUT_CSTYTLE = "E:\\CodeFile\\Compiler-LexicalAnalysis\\LexicalAnalysis\\SomeFile\\input_CStytle.txt";
const string OUTPUT_CSTYTLE = "E:\\CodeFile\\Compiler-LexicalAnalysis\\LexicalAnalysis\\SomeFile\\output_CStytle.txt";
const string KEYWORDS_CSTYTLE = "E:\\CodeFile\\Compiler-LexicalAnalysis\\LexicalAnalysis\\SomeFile\\keywords_CStytle.txt";
const string BOUNDARY_CSTYTLE = "E:\\CodeFile\\Compiler-LexicalAnalysis\\LexicalAnalysis\\SomeFile\\boundary_CStytle.txt";
const string OPERATOR_CSTYTLE = "E:\\CodeFile\\Compiler-LexicalAnalysis\\LexicalAnalysis\\SomeFile\\operator_CStytle.txt";
const string INPUT_SENTENCE = "E:\\CodeFile\\Compiler-LexicalAnalysis\\LexicalAnalysis\\SomeFile\\input_sentence.txt";//some flags of status
const int LETTER = 1; //字母
const int DIGIT = 2;//数字
const int OPERATOR = 3;//运算符
const int BOUNDARY = 4;//界符
const int END = 5;//结束符//读取的C源代码保存在vector数组中
vector<char>code_vector;//读入的关键字、运算符、界符保存在数组中
vector<string>keywords_vector;
vector<string>operator_vector;
vector<string>boundary_vector;//分析出的单词
struct Word
{string word_type;//单词类别string word_value;//单词值
};//存放单词的数组
vector<Word>word_vector;//the types of words
const string TOKEN = "token";//标识符
const string EASYOPERATOR = "operator";//运算符
const string EASYBOUNDARY = "boundary";//界符
const string KEYWORD = "keyword";//关键字
const string UNSIGNEDDIGIT = "digit";//数字
const string SPACE = "space";//赋值运算符
const string fuzhiOperator[] = { "=","+=","-=","/=","*=" };

五、语法分析源程序

说明:语法分析与词法分析在同一项目中
SynaxAnalysis:

/** @authot W-nut* FileInfo:语法分析*/#pragma once
#include 
#include "Constants.h"
using namespace std;
/*文法:
〈赋值语句〉∷= 〈标识符〉 = 〈表达式〉<表达式> ::=  <项> <运算符> <项> | <项> <项>::=<因子> <运算符> <因子> |<因子> 
〈因子〉∷= 〈标志符〉|〈无符号整数〉|(〈表达式〉)〈无符号整数〉∷= 〈数字〉|〈无符号整数〉〈数字〉
〈标识符〉∷= 〈字母〉|〈标识符〉〈字母〉|〈标识符〉〈数字〉
〈加法运算符〉∷= +|-
〈乘法运算符〉∷= *|/
*/int current = 0;//当前单词序号
vector<Word>noBlank_word;//没有空格void TokenAnalysis();
void ExpressionAnalysis();
void ItemAnalysis();
void FactorAnalysis();//判断current是否越界(true:越界;flase:未越界)
bool IsOutOfRange()
{if (current >= noBlank_word.size()-1)return true;elsereturn false;
}//判断是否是以字母开头
bool IsLetterFirst(const char ch)
{if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_')return LETTER;
}//判断是否为赋值运算符
bool IsOperatorEqual(const string ch)
{for (string op : fuzhiOperator){if (ch == op)return true;}return false;
}//总控程序
void SynaxAnalysis()
{for (Word word : word_vector){if (word.word_type == SPACE)continue;elsenoBlank_word.push_back(word);}//分析标识符TokenAnalysis();//分析赋值符号bool isOperatorEqual = IsOperatorEqual(noBlank_word[current].word_value);if (isOperatorEqual){++current;//分析下一单词(分析表达式)}else{//标识符后面不是赋值运算符cout << "SynaxError:标识符后面需要有赋值运算符!" << endl;exit(0);}//分析表达式ExpressionAnalysis();//分析结束标识 ;if (noBlank_word[current].word_value == ";"){//遇到 ; 结束cout << "Correct:语法检查正确!" << endl;return;}else{cout << "SynaxError:缺少结束界符“; ”" << endl;exit(0);}
}//标识符分析
//〈赋值语句〉∷= 〈标识符〉 = 〈表达式〉
void TokenAnalysis()
{bool isLetterFirst = IsLetterFirst(noBlank_word[current].word_value[0]);if (isLetterFirst){//首字符为字母或下划线if (noBlank_word[current].word_type == KEYWORD){//标识符为关键字cout << "SynaxError:赋值语句不能以关键字开头!" << endl;exit(0);}else{//首个单词是标识符if (IsOutOfRange()){//越界啦!return;}else{++current;//分析下一单词}return;}}else{//首字母不是字母或下划线cout << "SynaxError:赋值语句需要以标识符开头!" << endl;exit(0);}
}//函数说明:表达式分析
// <表达式> ::=  <项> <运算符> <项> | <项> 
void ExpressionAnalysis()
{ItemAnalysis();if (noBlank_word[current].word_type == EASYOPERATOR){if (IsOutOfRange()){//越界啦!return;}else{++current;//继续读取下一单词}	ItemAnalysis();}else{return; //表达式:=项}
}//函数说明:项分析
// <项>::=<因子> <运算符> <因子> |<因子> 
void ItemAnalysis()
{FactorAnalysis();if (noBlank_word[current].word_type == EASYOPERATOR){//下一单词是运算符if (IsOutOfRange()){//越界啦!return;}else{++current;//继续读取下一单词}FactorAnalysis();}else{return;}
}//函数说明:因子分析
//〈因子〉∷= 〈标识符〉|〈无符号整数〉|(〈表达式〉)
void FactorAnalysis()
{if (noBlank_word[current].word_type == TOKEN || noBlank_word[current].word_type == UNSIGNEDDIGIT){if (IsOutOfRange()){//越界啦!return;}else{++current;//分析下一个单词}return;}if (noBlank_word[current].word_value == "("){//左括号if (IsOutOfRange()){//越界啦!return;}else{++current;}ExpressionAnalysis();if (noBlank_word[current].word_value == ")"){if (IsOutOfRange()){//越界啦!return;}else{++current;//读取右括号继续读取}}else{cout << "SynaxError:缺少右括号!" << endl;return;}}else{//没有表达式cout << "SynaxError:表达式错误!" << endl;return;}
}

六、实验报告免费下载

文件资源已上传,戳我直达,biubiubiu~
实验报告

七、Last but not least

传说五大秘术:点赞、评论、分享、收藏、打赏!

mua~~


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部