編譯原理頭歌實驗:詞法分析程序設計與實現(C語言版)
1.實驗描述
任務描述
本關任務:加深對詞法分析器的工作過程的理解;加強對詞法分析方法的掌握;能夠采用一種編程語言實現簡單的詞法分析程序;能夠使用自己編寫的分析程序對簡單的程序段進行詞法分析。
編程要求
根據提示,在右側編輯器補充代碼標示符、數字符及其他字符符號的識別程序后,點擊評測運行程序,系統會自動進行結果對比。
測試說明
平臺會對你編寫的代碼進行測試:
測試輸入:
using namespace std; int main() {
int year;
cout << “hello” << endl;
return 0; }
2.實驗操作提示
2.1定義目標語言的可用符號表和構詞規則。
我們需要對五種單詞符號進行識別分析,這里將單詞符號分為三大塊進行識別。首先判斷字符是否為關鍵字或者標識符,并與已定義好的關鍵字進行比較,從而判斷為關鍵字或者標識符;然后是數字的識別;最后是其他字符的判斷,它們被一一定義好的判斷進行識別,這樣所有的字符便被識別出來了。標示符和關鍵字的判斷
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) //可能是標示符或者關鍵字
字符與關鍵字的區別通過對比得出:
if (strcmp(token, rwtab1[n]) == 0){syn = 2;break;}else if (strcmp(token, rwtab[n]) == 0) {syn = 1;break;}}
對于數字的識別:
else if ((ch >= '0' && ch <= '9')) //數字
其他字符的識別,他們被一一定義進行識別:
else switch (ch) //其他字符 {case'<':m = 0; token[m++] = ch;ch = prog[p++];if (ch == '>'){syn = 4;token[m++] = ch;}else if (ch == '='){syn = 4;token[m++] = ch;}else{syn = 4;p--;}break;case'>':m = 0; token[m++] = ch;ch = prog[p++];if (ch == '='){syn = 4;token[m++] = ch;}else{syn = 4;p--;}break;case':':m = 0; token[m++] = ch;ch = prog[p++];if (ch == '='){syn = 4;token[m++] = ch;}else{syn = 4;p--;}break;case'*':syn = 4; token[0] = ch; break;case'/':syn = 4; token[0] = ch; break;case'+':syn = 4; token[0] = ch; break;case'-':syn = 4; token[0] = ch; break;case'=':syn = 4; token[0] = ch; break;case';':syn = 5; token[0] = ch; break;case',':syn = 5; token[0] = ch; break;case'(':syn = 5; token[0] = ch; break;case')':syn = 5; token[0] = ch; break;case'{':syn = 5; token[0] = ch; break;case'}':syn = 5; token[0] = ch; break;case'#':syn = 0; token[0] = ch; break;case'\n':syn = -2; break;default: syn = -1; break;}
}
依次讀入源程序符號,對源程序進行單詞切分和識別,直到源程序結束。
字符的輸入我們使用cin.get() 獲取,并切分保存在 prog中:
p = 0;row = 1;cout << "Please input string:" << endl;do{cin.get(ch);prog[p++] = ch;} while (ch != '#');p = 0;
對正確的單詞,按照它的種別以<種別碼,值>的形式保存在符號表中;
對不正確的單詞,做出錯誤處理。
單詞識別后,我們對返回的符號按3,4的規則進行輸出:
{scaner();switch (syn){case 0: break;case 3: cout << "(" << syn << "," << sum << ")" << endl; break;case -1: cout << "Error in row " << row << "!" << endl; break;case -2: row = row++; break;default: cout << "(" << syn << "," << token << ")" << endl; break;}} while (syn != 0);
3.實驗代碼展示
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
char prog[1000], token[20];
char ch;
int syn, p, m = 0, n, row = 1, sum = 0;
// 擴充關鍵字表
const char* rwtab[10] = { "if","int","for","while","do","return","break","continue", "using", "namespace" };
const char* rwtab1[8] = { "main","a","b","c","d","e","f","g" };void scaner()
{// 初始化token數組for (n = 0; n < 20; n++) token[n] = '\0';// 跳過空白字符while (p < strlen(prog) && (prog[p] == ' ' || prog[p] == '\t' || prog[p] == '\n')){if (prog[p] == '\n')row++;p++;}if (p >= strlen(prog)){syn = 0;return;}ch = prog[p++];// 進行標示符或者關鍵字的識別if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')){m = 0;while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')){token[m++] = ch;if (p >= strlen(prog))break;ch = prog[p++];}token[m] = '\0';if (p < strlen(prog))p--;syn = 2;for (n = 0; n < 10; n++) // 更新關鍵字表長度{if (strcmp(token, rwtab[n]) == 0){syn = 1;break;}}}// 進行數字的識別else if (ch >= '0' && ch <= '9'){sum = 0;while (ch >= '0' && ch <= '9'){sum = sum * 10 + (ch - '0');if (p >= strlen(prog))break;ch = prog[p++];}if (p < strlen(prog))p--;syn = 3;}// 進行其他字符的識別else{switch (ch){case '<':m = 0;token[m++] = ch;if (p < strlen(prog) && prog[p] == '<'){token[m++] = prog[p++];syn = 4;}else{syn = 4;p--;}break;case '>':m = 0;token[m++] = ch;if (p < strlen(prog) && prog[p] == '='){token[m++] = prog[p++];syn = 4;}else{syn = 4;p--;}break;case ':':m = 0;token[m++] = ch;if (p < strlen(prog) && prog[p] == '='){token[m++] = prog[p++];syn = 4;}else{syn = 4;p--;}break;case '*':syn = 4;token[0] = ch;break;case '/':syn = 4;token[0] = ch;if (p < strlen(prog) && prog[p] == '/') {token[1] = '/';syn = 5; // 注釋符號作為界符處理p++;}break;case '+':syn = 4;token[0] = ch;break;case '-':syn = 4;token[0] = ch;break;case '=':syn = 4;token[0] = ch;break;case ';':syn = 5;token[0] = ch;break;case ',':syn = 5;token[0] = ch;break;case '(':syn = 5;token[0] = ch;break;case ')':syn = 5;token[0] = ch;break;case '{':syn = 5;token[0] = ch;break;case '}':syn = 5;token[0] = ch;break;case '#':syn = 0;token[0] = ch;break;case '"':syn = 5;token[0] = ch;break;default:syn = -1;break;}}
}int main()
{// 輸入p = 0;cout << "Please input string:" << endl;do{cin.get(ch);prog[p++] = ch;} while (ch != '#');prog[p] = '\0';p = 0;// 輸出do{scaner();switch (syn){case 0:break;case 3:cout << "(" << syn << "," << sum << ")" << endl;break;case -1:cout << "Error in row " << row << "!" << endl;break;default:cout << "(" << syn << "," << token << ")" << endl;break;}} while (syn != 0);return 0;
}
這個詞法分析器通過逐字符讀取輸入,根據字符的類型和上下文規則,識別出關鍵字、標識符、數字、運算符和分隔符。它能正確處理簡單的 C++ 代碼段,并輸出每個記號的類型和內容。程序設計清晰,邏輯分明,適合學習詞法分析的基本原理。
希望這個講解能幫助你深入理解代碼的實現過程!如果有疑問,歡迎評論區交流!