程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 詞法分析器(C語言版)

詞法分析器(C語言版)

編輯:C++入門知識

詞法分析器: 有限狀態機的理論並不難,但是如果把狀態機理論轉換成代碼,這個就需要思考了   數據結構設計: [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;   }        

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved