词法分析和语法分析1
为了造福大众,你懂的
一.实验目的
1.创建一个词法分析程序,该程序支持分析常规语法。必须使用DFA(确定性有限自动机)或NFA(不确定性有限自动机)来实现此程序。程序有两个输入:一个本文档,包括一组3°语法(正规文法)的产生式;一个源代码文本文档,包括一组需要识别的字符串。程序的输出是一个令牌表,该表由五种token组成:关键词,标识符,常量,限定符和运算符。
2.创建一个采用LL(1)方法或LR(1)方法的语法分析程序。程序的输入是一个文本文件包括一组的2°文法生成(上下文无关文法)产生式集合和任务1生成的token令牌表。该程序的输出是yes或no,即,这源代码的字符串是否符合这2°语法。
二.说明
src里面是源代码,编译需要配置qt环境
Executable里面是编译好的exe文件
运行后:
Function Choose底下选择词法分析还是语法分析,词法分析成功后才能分析语法。
Load选项加载测试的代码文件,然后选择uage文件夹底下词法分析的5个词法规则文件,共有常量(支持浮点和科学计数法),标识符、关键字、界符和操作符5种词法。
加载完成后没有提示,直接点run运行,可以看到输出token表,词法分析完成,同目录下会生成一个中间文件用于保存token。
然后Function Choose切到语法分析,测试代码和token表自动填好了,选择load语法规则文件,只有一个,加载成功后可以看到左下角的LR分析表(Action和Goto表合并了)。
然后再run,右下角显示分析过程,右上角显示分析结果(yes/no)。
另外,程序不支持打开中文路径底下的文件,支持的词法和语法有限。
三.词法
词法规则文件内容共分为五种,作为词法分析的依据。
1. 常量
[const]->'NUMBER'"C"
"C"->'NUMBER'"C"
"C"->'.'"G"
"C"->'e'"E"
"C"->'E'"E"
"C"->''
"C"->'i'
[const]->'.'"D"
"D"->'NUMBER'"G"
"G"->'NUMBER'"G"
"G"->'e'"E"
"G"->'E'"E"
"G"->''
"G"->'i'
"E"->'+'"H"
"E"->'-'"H"
"E"->'NUMBER'"I"
"H"->'NUMBER'"I"
"I"->'NUMBER'"I"
"I"->''
"I"->'i'
2. 标识符
[identifier]->'LETTER'
[identifier]->'LETTER'"L"
"L"->'LETTER'"L"
"L"->'NUMBER'"L"
"L"->'LETTER'
"L"->'NUMBER'
3. 界符
[limiter]->';'
[limiter]->','
[limiter]->'('
[limiter]->')'
[limiter]->'{'
[limiter]->'}'
[limiter]->','
4. 关键字
[keyword]->'void'
[keyword]->'int'
[keyword]->'double'
[keyword]->'char'
[keyword]->'if'
[keyword]->'else'
[keyword]->'for'
[keyword]->'break'
[keyword]->'continue'
[keyword]->'return'
5. 操作符
[operator]->'+'
[operator]->'-'
[operator]->'*'
[operator]->'/'
[operator]->'%'
[operator]->'='
[operator]->'<'
[operator]->'>'
[operator]->'+'"op"
[operator]->'-'"op"
[operator]->'*'"op"
[operator]->'/'"op"
[operator]->'%'"op"
[operator]->'='"op"
[operator]->'<'"op"
[operator]->'>'"op"
"op"->'='
[operator]->'+'"A"
"A"->'+'
[operator]->'-'"S"
"S"->'-'
四.语法
[START]->"X"
"X"->'@'
"X"->"FUN""X"
"STYLE"->'void'
"STYLE"->'int'
"FUN"->"STYLE"'identifier''('')''{'"STATEMENTS"'}'
"FUN"->"STYLE"'identifier''('"PRALIST"')''{'"STATEMENTS"'}'
"PRALIST"->"PRA""EXRTA"
"EXRTA"->','"PRA"
"EXRTA"->'@'
"PRA"->"STYLE"'identifier'
"CALLPRALIST"->"VALUE""EXRTAB"
"EXRTAB"->'@'
"EXRTAB"->','"VALUE"
"BLOCK"->'{'"STATEMENTS"'}'
"STATEMENTS"->'@'
"STATEMENTS"->"STATEMENT""STATEMENTS"
"STATEMENT"->"EXPRESSION"';'
"STATEMENT"->"DEFINE"';'
"STATEMENT"->'identifier''('')'';'
"STATEMENT"->'identifier''('"CALLPRALIST"')'';'
"STATEMENT"->"BRANCH"
"STATEMENT"->'return'';'
"STATEMENT"->'return'"EXPRESSION"';'
"BRANCH"->'if''('"EXPRESSION"')'"BLOCK"
"EXPRESSION"->"VALUE"'operator'"VALUE"
"EXPRESSION"->"VALUE"'operator'"VALUE"
"VALUE"->'('"EXPRESSION"')'
"VALUE"->'identifier'
"VALUE"->'const'
"DEFINE"->"STYLE"'identifier'
"DEFINE"->"STYLE"'identifier''operator'"EXPRESSION"
"BLOCK"->"STATEMENT"
"BLOCK"->'{'"STATEMENTS"'}'
五.模块设计以及程序主要代码
1.分析器主要流程:
2.模块设计:
主函数模块:程序开始,设计简单,主要调用窗体模块;
窗体模块:主要分为两部分,一是窗口的设计部分,定义页面分布以及功能按钮的实现,创造界面,二是调用功能函数;
功能函数模块:功能函数分别是词法分析和语法分析,语法分析建立在词法分析基础上,需要先进行词法分析。主要功能包括文件输入与输出,产生式的读入,对单词种类的判断,对输入字符串的判断等等。
模块关系图如下
3.Main函数:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
4.Mainwindow:
主要构造了界面以及文法文件,测试代码的读入与中间文件,分析结果的输出,构造并显示分析表。
1. 读入测试代码
void MainWindow::on_actionLoad_TestCode_triggered()
{
if(funcChoose==0){
QMessageBox::warning(this, tr("Analyzer"),tr("请先进行功能选择"));
return;
}
QString fileName = QFileDialog::getOpenFileName(this,"select testcode");
if (!fileName.isEmpty()) {
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, tr("分析器"),
tr("无法读取文件 %1:\n%2.")
.arg(fileName).arg(file.errorString()));
return; // 只读方式打开文件,出错则提示,并返回false
}
QTextStream in(&file); // 新建文本流对象
QApplication::setOverrideCursor(Qt::WaitCursor);
// 读取文件的全部文本内容,并添加到编辑器中
ui->textEdit_1->setPlainText(in.readAll());
QApplication::restoreOverrideCursor();
}
}
2. 读入文法
void MainWindow::on_actionLoad_Grammer_triggered()
{
if(funcChoose==1){ // 词法分析则有多个
if(lexical!=NULL)delete lexical;
lexical=new Lexical();
ui->textEdit_2->clear();
QStringList fileNames = QFileDialog::getOpenFileNames(this,"select lexical");
for(int i=0;i<fileNames.size();i++){
QString qs=fileNames.at(i);
lexical->buildDFA(qs.toStdString());
}
}
else if(funcChoose==2){ // 语法分析只需一个文法
if(syntax!=NULL)delete syntax;
syntax=new Syntax();
// ui->textEdit_2->clear();
QString fileName = QFileDialog::getOpenFileName(this,"select syntax");
if (!fileName.isEmpty()) {
syntax->run(fileName.toStdString());
displayAnalysisTable();
}
}
else {
QMessageBox::warning(this, tr("Analyzer"),tr("请先进行功能选择"));
return;
}
}
void MainWindow::on_actionrun_triggered()
{
int x;
if(funcChoose==1){
if(lexical==NULL){
QMessageBox::warning(this, tr("Analyzer"),tr("请先读入文法"));
return;
}
int wordNumber=0;
ui->textEdit_2->clear();
lexical->tokenTable.clear();
QString text = ui->textEdit_1->toPlainText();
QStringList list = text.split("\n");
std::ofstream out(OUTPUTFILE,std::ios::out); // 将单词序列输出到中间文件
for(int k=0;k<list.size();k++){
string line=list.at(k).toStdString();
for(int i=0;i<line.size();){
while(line[i]<=' ')i++;
if(!lexical->lexical_analysis(line,i)){
for(int i=0;i<lexical->tokenTable.size();i++){
ui->textEdit_2->append(QString::fromStdString(lexical->tokenTable[i]));
}
QMessageBox::warning(this, tr("Analyzer"),tr("出错,有未知单词"));
out.close();
return;
}
string addText=""+std::to_string(wordNumber)+" "+lexical->wordType+" "+lexical->id;
lexical->tokenTable.push_back(addText);
if(lexical->wordType==KEYWORDS||lexical->wordType==LIMITER){
out<<lexical->id<<'\n';
}
else {
out<<lexical->wordType<<'\n';
}
// ui->textEdit_2->append(QString::fromStdString(addText));
wordNumber++;
}
}
out.close();
for(int i=0;i<lexical->tokenTable.size();i++){
ui->textEdit_2->append(QString::fromStdString(lexical->tokenTable[i]));
}
QMessageBox::warning(this, tr("Analyzer"),QString::fromStdString("发现了"+std::to_string(wordNumber)+"个单词"));
}else if(funcChoose==2){
if(syntax==NULL){
QMessageBox::warning(this, tr("Analyzer"),tr("请先读入文法"));
return;
}
{
vector<string> st=syntax->readTest(OUTPUTFILE);
st.pop_back();
st.push_back("#");
if(syntax->startAnalysis(st)){
ui->textEdit_3->setText("yes");
// QMessageBox::warning(this, tr("Analyzer"),tr("是"));
}else{
ui->textEdit_3->setText("no");
// QMessageBox::warning(this, tr("Analyzer"),tr("否"));
}
displayAnalysisProcess();
QMessageBox::warning(this, tr("Analyzer"),tr("分析完成"));
}
}else{
QMessageBox::warning(this, tr("Analyzer"),tr("请先进行功能选择"));
return;
}
}
3.显示分析表
void MainWindow::displayAnalysisTable(){
QStandardItemModel* model = new QStandardItemModel(ui->tableView);
model->setColumnCount(syntax->columnName.size());
for(int i=0;i<syntax->columnName.size();i++){
model->setHeaderData(i,Qt::Horizontal, QString::fromStdString(syntax->columnName[i]));
}
model->setRowCount(syntax->analysisTable.size());
for(int i=0;i<syntax->analysisTable.size();i++){
model->setHeaderData(i,Qt::Vertical,tr("%1").arg(i));
for(int k=0;k<syntax->columnName.size();k++){
string temp;
switch (syntax->analysisTable[i][k].type) {
case moveIn:
temp='S'+std::to_string(syntax->analysisTable[i][k].num);
break;
case reduce:
temp='r'+std::to_string(syntax->analysisTable[i][k].num);
break;
case shift:
temp=std::to_string(syntax->analysisTable[i][k].num);
break;
case accept:
temp="acc";
break;
case error:
temp="";
break;
default:
break;
}
model->setItem(i, k, new QStandardItem(QString::fromStdString(temp)));
}
}
ui->tableView->setModel(model);
}
5.词法分析主要代码
给出文法的路径,读取文法并构造DFA
void Lexical::buildDFA(string path){
ifstream in;
in.open(path, ios::in);
string rule;
vector<node_FA> NFAs;
vector<string> allSides;
while(getline(in,rule)){ int i=0;
int k = 0;
if (rule[0] == '[') { // 开始符号
startName = getStringBetween(rule, '[', ']', i);
k = searchNFA(NFAs, startName);
NFAs[k].state = startSym;
if (find(wordTypes.begin(), wordTypes.end(), startName) == wordTypes.end()) // 一个新的单词种类
wordTypes.push_back(startName);
}
else if (rule[0] == '"') { // 非终结符
startName = getStringBetween(rule, '"', '"', i);
k = searchNFA(NFAs, startName);
NFAs[k].state = middleSym;
}
while (1) {
if (rule[i] == '-'&&rule[i + 1] == '>')break;
i++;
}
// 终结符
sideName = getStringBetween(rule, '\'', '\'', i);
// 一条边对应一个目的状态
NFAs[k].side.push_back(sideName);
if (find(allSides.begin(), allSides.end(), sideName) == allSides.end())
allSides.push_back(sideName);
// 非终结符,可能没有
endName = getStringBetween(rule, '"', '"', i);
if (endName == "")endName = FINAL_STATE;
NFAs[k].end.push_back(endName);
if (startName == KEYWORDS) { // 是关键字
keywords.push_back(sideName);
}
}
in.close();
// 构造DFA
vector<node_FA> DFAs;
node_FA temp;
temp.start = NFAs[0].start;
temp.state = unmarked;
DFAs.push_back(temp);
vector<int> unmarkedLabel; // 保存未标记的DFA,与DFA在向量中的顺序一致
unmarkedLabel.push_back(0);
while (unmarkedLabel.size() != 0) { // C(DFAs)中存在尚未标记的T
int now = unmarkedLabel[0]; // 弹出当前未标记的T的位置now
unmarkedLabel.erase(unmarkedLabel.begin());
// 标记T
if (now == 0)DFAs[now].state = startSym;
else {
DFAs[now].state = middleSym;
for (int i = 0; i < DFAs[now].start.size(); i++) {
if (DFAs[now].start[i] == FINAL_STATE) {
DFAs[now].state = endSym;
break;
}
}
}
// 对每条边求Move
for (int i = 0; i < allSides.size(); i++) { // 对于每条边a
string sideName = allSides[i];
node_FA tempDFA; // U = move(T,a)
for (int k = 0; k < DFAs[now].start.size(); k++) { // T里的每个状态
string startName = DFAs[now].start[k];
if (startName == FINAL_STATE)continue;
for (int t = 0; t < NFAs.size(); t++) { // 去NFA寻找这个状态
if (startName == NFAs[t].start[0]) { // 找到,走完就可以直接break了
for (int z = 0; z < NFAs[t].side.size(); z++) { // 寻找该状态经过该边可以到达的状态
if (NFAs[t].side[z] == sideName) {
tempDFA.start.push_back(NFAs[t].end[z]);
}
}
break;
}
}
}
if (tempDFA.start.size() == 0) continue; // 从该边没有可以到达的路
sort(tempDFA.start.begin(), tempDFA.start.end()); // 排序,方便比较
// U是否在C中
int flag = 0;
int position;
for (int i = 0; i < DFAs.size(); i++) {
if (equalVector(tempDFA.start, DFAs[i].start)) {
flag = 1;
position = i;
break;
}
}
if (!flag) { // 不在C中
tempDFA.state = unmarked;
position = DFAs.size(); // 加入C最后,记为Tn
DFAs.push_back(tempDFA);
unmarkedLabel.push_back(position);
}
// 增加边和目的状态
DFAs[now].side.push_back(sideName);
DFAs[now].endNum.push_back(position);
}
}
allGrammer.push_back(DFAs);
}
6. 语法分析主要代码
/* 求非终结符的first集 */
void Syntax::calculateFirstsets() {
firstsets.resize(nonterminals.size());
vector<production> pros;
/* 若X->a... 就把a加入X的first集,并且删除该产生式 */
for (int i = 0; i < productions.size(); i++) {
if (productions[i].end[0].type == Terminal) {
vector<string> temp;
temp.push_back(productions[i].end[0].name);
int p = 0;
while (nonterminals[p] != productions[i].start)p++;
addVector(firstsets[p], temp);
}
else if (productions[i].end[0].type == Nonterminal) {
pros.push_back(productions[i]);
}
}
/* 若X->ABCD... */
int sum_new = 0;
for (int i = 0; i < firstsets.size(); i++) {
sum_new += firstsets[i].size();
}
int sum_old = -1;
while (sum_old != sum_new) {
sum_old = sum_new;
for (int i = 0; i < pros.size(); i++) {
vector<string> temp = searchFirstsetByString(pros[i].end);
int p = 0;
while (nonterminals[p] != pros[i].start)p++;
addVector(firstsets[p], temp);
}
// 判断是否继续
sum_new = 0;
for (int i = 0; i < firstsets.size(); i++) {
sum_new += firstsets[i].size();
}
}
}
/* 查询非终结符的frist集,usage决定需不需要去掉@ */
vector<string> Syntax::searchFirstset(string name, int usage) {
int i = 0;
while (nonterminals[i] != name)i++;
vector<string> temp;
for (int k = 0; k < firstsets[i].size(); k++) {
if (usage == 1 && firstsets[i][k] == "@")continue;
temp.push_back(firstsets[i][k]);
}
return temp;
}
/* 求出给定符号串的first集 */
vector<string> Syntax::searchFirstsetByString(vector<symble> syms) {
vector<string> firstsets;
for (int k = 0; k < syms.size(); k++) {
vector<string> temp;
if (syms[k].type == Terminal) { // 终结符,加入,并跳出
temp.push_back(syms[k].name);
addVector(firstsets, temp);
break;
}
else if (syms[k].type == Nonterminal) { // 非终结符,则加入该非终结符的first集
temp = searchFirstset(syms[k].name, 1);
addVector(firstsets, temp);
if (nonReachable(syms[k].name) == 1) { // 该非终结符能推出@
if (k == syms.size() - 1) { // 并且是最后一个
addVector(firstsets, vector<string>({ "@" }));
}
}
else break; // 该非终结符不能推出@
}
}
return firstsets;
}
/* 从项目集中查找一个项目,返回这个项目的位置 */
int Syntax::searchItemset(itemset item) {
for (int i = 0; i < itemsets.size(); i++) {
if (equalItemset(itemsets[i], item)) {
return i;
}
}
itemsets.push_back(item);
return (itemsets.size() - 1);
}
/* 对项目构造闭包 */
void Syntax::buildClosure(itemset &item){
for (int i = 0; i < item.productions.size(); i++) {
if (item.productions[i].point >= item.productions[i].end.size())continue; // ·在最后面无需求
// (item.productions[i].end[item.productions[i].point]) 表示当前项目第i条产生式的·所在位置的符号
if (pointSym(item, i).type == Nonterminal) { // A->·BX,a/b/c
vector<symble> symString; // 存储X
for (int k = item.productions[i].point + 1; k < item.productions[i].end.size(); k++) {
symString.push_back(item.productions[i].end[k]);
}
vector<string> firsts;
for (int k = 0; k < item.productions[i].faceSyms.size(); k++) { // 获得Xa,Xb..的first集
vector<symble> temp_symString(symString); // 获得Xa
temp_symString.push_back(symble{ item.productions[i].faceSyms[k],Terminal }); // 这里同时可以保证#被当做终结符处理
vector<string> temp_firsts = searchFirstsetByString(temp_symString); // Xa的first集
addVector(firsts, temp_firsts);
}
sort(firsts.begin(), firsts.end()); // 面临符号是排序好的,用于对于产生式的相等
for (int t = 0; t < productions.size(); t++) { // 向项目中加入左部为B的产生式
if (productions[t].start == pointSym(item, i).name) {
production temp_pro = productions[t];
temp_pro.position = t;
temp_pro.point = 0;
if (temp_pro.end[0] == symble{ "@",Terminal }) { // 产生式可以产生空,在项目中就去掉@,即A->·
temp_pro.end.clear();
}
if (hasProductionInItem(item, temp_pro,false) != -1) { // 有该产生式,将面临符号加进去
addVector(item.productions[i].faceSyms, firsts);
}
else { // 没有,就增加一条产生式
temp_pro.position = t;
temp_pro.faceSyms = firsts;
item.productions.push_back(temp_pro);
}
}
}
}
}
}
/* 创建LR(1)项目集,同时构造分析表 */
void Syntax::buildItemsets(){
// 分析表的相关初始化
for(int i=0;i<terminals.size();i++){
if(terminals[i]=="@")continue;
columnName.push_back(terminals[i]);
}
columnName.push_back("#");
for(int i=1;i<nonterminals.size();i++){
columnName.push_back(nonterminals[i]);
}
// 项目集的相关初始化
production t(productions[0]);
t.position = 0;
t.point = 0;
t.faceSyms.push_back("#");
itemset temp;
temp.coreNumber = 1;
temp.productions.push_back(t);
itemsets.push_back(temp);
buildClosure(itemsets[0]);
for (int i = 0; i < itemsets.size(); i++) { // 对所有项目
// 分析表初始所有都是出错
vector<behavior> temp_beh;
behavior b{error,0};
for(int t=0;t<columnName.size();t++){
temp_beh.push_back(b);
}
analysisTable.push_back(temp_beh);
vector<bool> hasVisited(itemsets[i].productions.size(), false); // 用于记录项目里的产生式有无被访问过
for (int k = 0; k < itemsets[i].productions.size(); k++) { // 该项目里的所有产生式
if (!hasVisited[k]) {
if (itemsets[i].productions[k].point < itemsets[i].productions[k].end.size()) { // 该产生式还有路可以走
hasVisited[k] = true;
vector<production> new_pros; // 存放新项目的所有核
symble temp_sym = pointSym(itemsets[i], k);
production temp_pro(itemsets[i].productions[k]);
temp_pro.point++;
new_pros.push_back(temp_pro);
int number = 1;
for (int t = k + 1; t < itemsets[i].productions.size(); t++) { // 检查有无输入符号相同的产生式
if (itemsets[i].productions[t].point >= itemsets[i].productions[t].end.size())continue;
if (pointSym(itemsets[i], t) == temp_sym) {
hasVisited[t] = true;
production temp_pro(itemsets[i].productions[t]);
temp_pro.point++;
new_pros.push_back(temp_pro);
number++;
}
}
itemset temp_itemset;
temp_itemset.productions = new_pros;
temp_itemset.coreNumber = number;
itemsets[i].side.push_back(temp_sym);
int foundItemset = searchItemset(temp_itemset);
itemsets[i].endState.push_back(foundItemset);
if (foundItemset == itemsets.size() - 1) { // 新的项目就直接求闭包
buildClosure(itemsets[foundItemset]);
}
// 终结符,移进
if(temp_sym.type==Terminal){
behavior heb;
heb.type=moveIn;
heb.num=foundItemset;
int col=getColumnInAnalysisTable(temp_sym.name);
analysisTable[i][col]=heb;
}else if(temp_sym.type==Nonterminal){ // 非终结符,转移
behavior heb;
heb.type=shift;
heb.num=foundItemset;
int col=getColumnInAnalysisTable(temp_sym.name);
analysisTable[i][col]=heb;
}
}else{
if(itemsets[i].productions[k].position==0){ // 接受
behavior heb;
heb.type=accept;
int col=getColumnInAnalysisTable("#");
analysisTable[i][col]=heb;
}else{ // 归约式
for(int t=0;t<itemsets[i].productions[k].faceSyms.size();t++){
behavior heb;
heb.type=reduce;
heb.num=itemsets[i].productions[k].position;
string faceName=itemsets[i].productions[k].faceSyms[t];
int col=getColumnInAnalysisTable(faceName);
analysisTable[i][col]=heb;
}
}
}
}
}
}
}
7. 分析过程及错误处理
/* 开始分析 */
bool Syntax::startAnalysis(vector<string> inputString){
analysisProcess.clear();
stateStack.clear();
stateStack.push_back(0);
symbleStack.clear();
symbleStack.push_back("#");
int state_p=0;
int symble_p=0;
for(int i=0;i<inputString.size();){
vector<string> process;
process.resize(5);
int col=getColumnInAnalysisTable(inputString[i]);
if(col==-1)return false;
int nextNum=analysisTable[stateStack[state_p]][col].num;
if(analysisTable[stateStack[state_p]][col].type==moveIn){ // 移进
for(int t=0;t<=state_p;t++){
process[0]+=std::to_string(stateStack[t])+' ';
}
for(int t=0;t<=symble_p;t++){
process[1]+=symbleStack[t]+' ';
}
process[2]=inputString[i];
process[3]='S'+std::to_string(nextNum);
analysisProcess.push_back(process);
stateStack.push_back(nextNum);
state_p++;
symbleStack.push_back(inputString[i]);
symble_p++;
i++;
}else if (analysisTable[stateStack[state_p]][col].type==reduce) { // 归约
for(int t=0;t<=state_p;t++){
process[0]+=std::to_string(stateStack[t])+' ';
}
for(int t=0;t<=symble_p;t++){
process[1]+=symbleStack[t]+' ';
}
process[2]=inputString[i];
process[3]='r'+std::to_string(nextNum);
for(int k=0;k<productions[nextNum].end.size();k++){
stateStack.pop_back();
state_p--;
symbleStack.pop_back();
symble_p--;
}
string startName=productions[nextNum].start;
int a=getColumnInAnalysisTable(startName);
int b=analysisTable[stateStack[state_p]][a].num;
stateStack.push_back(b);
state_p++;
symbleStack.push_back(startName);
symble_p++;
process[4]=std::to_string(b);
analysisProcess.push_back(process);
}else if (analysisTable[stateStack[state_p]][col].type==accept) { // 接受
if(inputString[i]=="#"){
for(int t=0;t<=state_p;t++){
process[0]+=std::to_string(stateStack[t])+' ';
}
for(int t=0;t<=symble_p;t++){
process[1]+=symbleStack[t]+' ';
}
process[2]=inputString[i];
process[3]="acc";
analysisProcess.push_back(process);
return true;
}
}else if (analysisTable[stateStack[state_p]][col].type==shift) { // 转移
}else{ // 出错
for(int t=0;t<=state_p;t++){
process[0]+=std::to_string(stateStack[t])+' ';
}
for(int t=0;t<=symble_p;t++){
process[1]+=symbleStack[t]+' ';
}
process[2]=inputString[i];
process[3]="error";
analysisProcess.push_back(process);
return false;
}
}
}
六.实验总结及感想
通过这次实验,更加深刻地了解并掌握编译原理知识,更深度学习词法分析以及语法分析地过程和原理,并且通过这次课设使自己对c++语言的运用理解更深,更加熟练,并且进一步掌握qt等工具的使用。更加熟悉了构造词法分析程序和语法分析程序的手工方式的相关原理,能够实现对词法和语法分析学以致用。