為了造福大眾,你懂的
一.實驗目的
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等工具的使用。更加熟悉了構造詞法分析程序和語法分析程序的手工方式的相關原理,能夠實現對詞法和語法分析學以致用。