詞法分析器: 有限狀態機的理論並不難,但是如果把狀態機理論轉換成代碼,這個就需要思考了 數據結構設計: [cpp] char charList[_CHARLIST_SIZE][15] = {0}; char charList_nu[_CHARLIST_SIZE] = {0}; char charList_index = 0; char numList[_NUMLIST_SIZE][15] = {0}; char numList_nu[_CHARLIST_SIZE] = {0}; char numList_index = 0; char delimilterList[_DELIMILTER_SIZE][15] = {0}; char delimilterList_nu[_DELIMILTER_SIZE] = {0}; char delimilterList_index = 0; 由於最後輸出需要看到非保留字和數字本身,以及出現的行號,所以這裡用三個變量來記錄,其中*_index 表示的數組的長度。 保留字: [cpp] char reserveList[_RESERVE_NUM][15] = { "void", "int", "char", "float", "double", "while", "auto", "break", "case", "const", "continue", "default", "do", "else", "enum", "extern", "for", "goto", "if", "long", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "volatile", "redister" }; Google後所查詢到的保留字,這裡我沒有發現main,由此可見main 應該是預處理的時候給處理掉了。 狀態機: 由於書上的內容不全,因此在編寫的時候在判斷 isLetter 加入了’_’,判斷數字的時候加入了+- 號的判斷,以及雙引號的判斷。 待編譯內容 [cpp] void _fun() { } int main() { int a = -111; int b = +1; printf("%d, a); return 0; } 可以看到這個代碼是正確的代碼。 運行後的結果,可以看到字符和常量已經分別出來了,這裡我就不截圖了,太麻煩。 在處理雙引號的時候,當匹配到第一個引號時,即是狀態機的初態,遇到下一個引號即到達終態,但是如果是錯誤代碼(如下圖),即無法到達終態,怎麼辦? 對於這種情況我沒有單獨處理,輸出結果如下: 我們看到這裡有一個總行數total nu 為7是錯誤的。因為我們在處理引號的初態時,始終無法匹配到第二個引號,自然也就始終把 /n 當成是引號中的內容,在以引號為初態的狀態機中跳轉。 關於回退指針,由於我沒有一次讀取到一個字符數組中,所以用了一個內置函數 ungetc,能將字符放回到流中 由於要以文本輸出,就用freopen,然後fprintf即可,如果用fputc的話只能單個的輸入。 對於數字的處理(下圖為樣例): 由此可見第一個是正確的輸入,後兩個均為不可識別的部分。下圖為我識別出的部分 原本我想的是這樣的識別肯定是錯誤的,因為它把不應該識別的部分也識別出來了,也就是說這裡存在語法錯誤。但是後來一想,這是對的,因為只要存在不識別的部分,就直接報錯。我們只需要關注需要識別的部分即可。這裡可以很清楚的看到我把-3.12e+1.11識別出來了。 如果要讓line 2和line 3不顯示東西的話,需要考慮的問題就是當終態出現的時候,比如識別+1e-e時,先識別 +1e-,然後當識別e 的時候,這裡出現了錯誤,無法到達終態。然後用ungetc回退,之後再次讀入e,這裡就當成了一個字符,即最後在line 2顯示出了e ,這就是原因。Line3也是。但是如我之前所說,只要出現識別不了的東西,直接報錯即可。我這裡通過返回error,並且這個error是用lastRetval全局變量來標識的,這和windows編程裡的getLastError有著一樣的意思。 由於是現學現寫,不免有部分是錯誤的。還望各位大神指點,而且目前對語法分析,和語義分析還不清楚。 代碼: [cpp] #include <stdio.h> #include <iostream> #include <cstring> #define NUMERROR -1 #define _RESERVE_NUM 32 #define _DELIMILTER_NUM 8 #define _DELIMILTER_SIZE 100 #define _CHARLIST_SIZE 100 #define _NUMLIST_SIZE 100 #define _TOKEN_SIZE 100 #define COL 1000 #define LT 1 #define LE 2 #define EQ 3 using namespace std; FILE* fp; int lastRetval = 0; char charList[_CHARLIST_SIZE][15] = {0}; char charList_nu[_CHARLIST_SIZE] = {0}; char charList_index = 0; char numList[_NUMLIST_SIZE][15] = {0}; char numList_nu[_CHARLIST_SIZE] = {0}; char numList_index = 0; char delimilterList[_DELIMILTER_SIZE][15] = {0}; char delimilterList_nu[_DELIMILTER_SIZE] = {0}; char delimilterList_index = 0; char reserveList[_RESERVE_NUM][15] = { "void", "int", "char", "float", "double", "while", "auto", "break", "case", "const", "continue", "default", "do", "else", "enum", "extern", "for", "goto", "if", "long", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "volatile", "redister" }; char delimilter[_DELIMILTER_NUM][5] = { "+", "-", "*", "/", "<", ";", "<=", "==" // six plus two }; void nu_print(int nu) { int i, cindex, nindex, flag, hasPrint; cindex = nindex = 0; printf("\n======================== each line to see =========================\n"); for(i = 0; i < nu; i++) { hasPrint = 0; for( ; cindex <= charList_index || nindex <= numList_index; ) { flag = 0; if(charList_nu[cindex] == i+1) { if(0 == hasPrint) { printf("\nline %d\n", i+1); hasPrint = 1; } printf(" %s ", charList[cindex]); ++cindex; flag = 1; } if(numList_nu[nindex] == i+1) { if(0 == hasPrint) { printf("\nline %d\n", i+1); hasPrint = 1; } printf(" %s ", numList[nindex]); ++nindex; flag = 1; } if(0 == flag) break; } } } void _print(int nu) { int i, j; printf("\n============== char of list ================\n"); for(i = 0; i < charList_index; i++) { printf("%s nu: %d\n", charList[i], charList_nu[i]); fprintf(fp,"%s nu: %d\n", charList[i], charList_nu[i]); } printf("\n============== const number of list ================\n"); for(i = 0; i < numList_index; i++) { printf("%s nu: %d\n", numList[i], numList_nu[i]); fprintf(fp, "%s nu:%d\n", numList[i], numList_nu[i]); } printf("\ntotal nu: %d\n", nu); } bool isLetter(char a){ if((a <= 'Z' && a >= 'A') || (a <= 'z' && a >= 'a') || '_' == a) { return true; } else return false; } bool isDigit(char a) { if(a <= '9' && a >= '1') { return true; } else return false; } void concatenation(char token[_TOKEN_SIZE], char str) { int len = strlen(token); token[len] = str; } int reserve(char token[_TOKEN_SIZE]) { int i, j; for(i = 0; i < _RESERVE_NUM; i++) { if(!strcmp(&reserveList[i][0], token)) { return 1; } } for(i = 0; i < _DELIMILTER_NUM; i++) { if(!strcmp(&delimilter[i][0], token)) { return 2; } } return 0; } int buildCharList(char token[_TOKEN_SIZE]) { strcpy(&charList[charList_index][0], token); ++charList_index; return charList_index-1; } int buildNumList(char token[_TOKEN_SIZE]) { strcpy(&numList[numList_index][0], token); ++numList_index; return numList_index-1; } int analysisCode(char str, int& nu) { int num; char token[_TOKEN_SIZE]; memset(token, 0, sizeof(token)); if('\n' == str) { ++nu; return '\n'; } else if(isLetter(str)) { while(isLetter(str) || isDigit(str)) { concatenation(token, str); str = getchar(); } ungetc(str, stdin); int type = reserve(token); if(0 == type) { num = buildCharList(token); charList_nu[num] = nu; } memset(token, 0, sizeof(token)); return num; } else if(isDigit(str) || '+' == str || '-' == str) { if(NUMERROR == lastRetval) { return NUMERROR; } int dotFlag, eFlag, numFlag, fFlag; int eNum, dotNum, fNum; dotFlag = eFlag = 0; numFlag = fFlag = 1; eNum = dotNum = fNum = 0; while(isDigit(str) || 'e' == str || '.' == str || '+' == str || '-' == str) { if('e' == str) { if(0 == eFlag || 1 == eNum) { ungetc(str, stdin); return NUMERROR; } dotFlag = 0; eFlag = 0; numFlag = 1; fFlag = 1; ++eNum; dotNum = 0; fNum = 0; } else if('+' == str || '-' == str) { if(0 == fFlag || 1 == fNum) { ungetc(str, stdin); return NUMERROR; } dotFlag = 0; eFlag = 0; numFlag = 1; fFlag = 0; ++fNum; } else if('.' == str) { if(0 == dotFlag || 1 == dotNum) { ungetc(str, stdin); return NUMERROR; } dotFlag = 0; eFlag = 0; numFlag = 1; fFlag = 0; ++dotNum; } else if(isDigit(str)) { dotFlag = 1; eFlag = 1; numFlag = 1; fFlag = 0; } concatenation(token, str); str = getchar(); } ungetc(str, stdin); num = buildNumList(token); numList_nu[num] = nu; memset(token, 0, sizeof(token)); return num; } else if('"' == str) { int flag = 0; while(0 == flag) { concatenation(token, str); str = getchar(); if('"' == str) { flag = 1; } } concatenation(token, str); } else { for(int i = 0; i < 6; i++) { if(delimilter[i][0] == str) { return str; } } if('<' == str) { str = getchar(); if('=' == str) { return LE; } ungetc(str, stdin); return LT; } if('=' == str) { str = getchar(); if('=' == str) { return EQ; } ungetc(str, stdin); return '='; } } // return NUMERROR; } int main() { freopen("t1.txt", "rw", stdin); fp = fopen("D://file.txt", "w"); char str; char token[_TOKEN_SIZE]; int nu = 1; memset(token, 0, sizeof(token)); while(scanf("%c", &str) != EOF) { lastRetval = analysisCode(str, nu); } _print(nu-1); nu_print(nu-1); fclose(stdin); return 0; }