這是偶然翻出來的一段大學時的代碼——詞法分析器又稱掃描器。詞法分析是指將咱們編寫的文本代碼流解析爲一個一個的記號,分析獲得的記號以供後續語法分析使用。詞法分析器的工做是低級別的分析:將字符或者字符序列轉化成記號.。在談論詞法分析時,咱們使用術語「詞法記號」(簡稱記號)、「模式」和「詞法單元」表示特定的含義。
在分析時,一是把詞法分析器當成語法分析的一部分,另外一種是把詞法分析器當成編譯程序的獨立部分。在前一種狀況下,詞法分析器不斷地被語法分析器調用,每調用一次詞法分析器將從源程序的字符序列拼出一個單詞,並將其Token值返回給語法分析器。後一種狀況則不一樣,詞法分析器不是被語法分析器不斷地調用,而是一次掃描所有單詞完成編譯器的獨立一遍任務。
詞法分析器主要特色是不依靠語法,而只依靠詞法,即處理一個單詞時不依賴於外部單詞的信息,所以詞法分析器通常都很簡單。固然,對某些語言在做詞法分析時,在有些狀況下不得不往前查看多個字符,有時還要作一些特殊處理,還有一些在詞法分析中處理不了的,要留到語法分析中進行處理。 git
本算法主要利用狀態轉換圖生成一個詞法分析器,對輸入的程序進行詞法分析,並將分析獲得的單詞造表。其中關鍵字表和界限符表的大小是由高級語言的子集決定的,能夠用數組裝載;而標識符表和常數表的大小取決於輸入的待分析程序中的變量、過程名、常數的個數,因此要用指針組成動態鏈表來裝載。當爲未了方便,咱們也把它定義成數組處理。算法
語法分析時,調用詞法分析器,根據已知文法利用遞歸向下分析,檢查語法錯誤。小程序
本程序爲類C編譯程序,詞法分析時能識別各類關鍵字、標識符、常數、界符,、算符,可以剔除註釋內容(支持單行註釋及多行註釋),語法分析等分析C語言中的一個小程序,程序體中能夠進行變量聲明、簡單賦值語句、帶表達式的複雜賦值語句等內容。數組
程序在Microsoft Visual C++ 6.0 中運行經過。ide
/************************************************************************/ /* 使用說明:在程序所在工做目錄下創建一個文本文檔取名爲file.txt,並在其中 輸入待分析代碼。改程序能分析一簡單的C語言程序:頭文件、函數。函數體中可包 含變量的定義、聲明、賦值語句、條件語句、循環語句等,其中賦值語句中的賦值表 達式能夠是任何知足四則混合運算的表達式。 頭文件 :#include < stdio.h > #inclide " scanner.c " 變量聲明 :int sum ,num1i,num2i,num ; int flag ; bool T ; 賦值語句 :sum = num1i + num2i * (num1i / (num2i + num)) flag = 1 ; T = true ; 條件語句 :if(num <= 30) { …… } if( flag ) { …… } 循環語句 :while( true ){ …… } while( flag ){ …… } while( 1 ){ …… } while( T ){ …… } while( num == 20 ){ …… } for( num = 0; num < 100; num += 2 ){ …… } for( num = 100; num >= 0; num -- ){ …… } 做者 :車水碼農 更新時間 :2009.4.24 最後更新 :2009.5.27 更新內容 :增長了條件語句、增量語句,更新了部分函數名,替換部分空語句爲reutrn; 最末錯誤標記代碼143 最後更新 :2009.5.28 更新內容 :對代碼作了一小部分修改,可有可無 最後更新 :2009.5.29 更新內容 :添加了部分註釋,對說明文件作了補充 最後更新 :2009.5.30 更新內容 :添加了返回值語句,錯誤代碼152 */ /************************************************************************/ #include<stdio.h> #include<stdlib.h> #include <ctype.h> #include<string.h> FILE *fp; int Line = 1; int Valuei; float Valuef; char *type; int err_count=0; //標識符表 struct id_Table { char id_Name[15];//函數、變量名 char *id_type;//類型(int void) char *id_Attrib;//屬性(函數,變量?) float id_Valuef; int id_Valuei; int id_Beg;//做用域開始標記 int id_End;//做用域結束標記 }ID[500]; //常數表 struct num_Table { char num[10];//常數串 char *num_Type;//數據類型 }NUM[100]; char *token="";//存放詞法分析時的單詞 char *headerFile[10]; int keyCount = 32;//關鍵字個數 char *key[] = {"auto","break","case","char","const","continue","default", "do","double","else","enum","extern","float","for", "goto","if","int","long","register","return","short", "signed","static","sizeof","struct","switch","typedef","union", "unsigned","void","volatile","while"};//關鍵字 int opPoint = 0; int numPoint = 0; int headerPoint = 0; char ch; //判斷空格 int space(char ch) { return isspace(ch); } //判斷字母 int letter(char ch) { return isalpha(ch); } //判斷數字 int digit(char ch) { return isdigit(ch); } //出錯處理 void error(int i,int line,char *str) { err_count++; printf(" error:%2d, Line: %2d : %s\n",i,line,str); // printf("\n The source file:%d error(s)\n\n\n",err_count); } //將讀入的單個字符組成單詞存放於token中 void concatennation(char ch) { int i = strlen(token); token[i] = ch; token[i+1] = '\0'; } //查關鍵字表 int reserve(char *token) { for(int i=0;i<keyCount;i++) { if(!strcmp(token,key[i])) return i+1;//是保留字返回其編碼 } return 0;//不是返回0 } //文件指針回退 void retract(FILE *fp,char ch) { fseek(fp,-1l,SEEK_CUR); ch = ' '; } //建表 int buildlist(char *token,int tag) { int i =0; int position = -1; switch (tag) { case 0: //標識符表 for(i=0;i<opPoint;i++) { if(!strcmp(ID[i].id_Name,token))//同一標識符再次出現 position = i; //返回其表中位置 } if(-1 == position) { strcpy(ID[opPoint].id_Name,token);//不然追加在表尾 position = opPoint; opPoint++; } break; case 1://常數表 strcpy(NUM[numPoint].num,token);//將常數加入常數表中 position = numPoint; numPoint++; break; case 2://頭文件 headerFile[headerPoint] = (char *)malloc(15); for(i=0;i<headerPoint;i++) { if(!strcmp(headerFile[i],token))//假如相等 position = i; } strcpy(headerFile[headerPoint],token); position = headerPoint; headerPoint++; break; } return position; } /************************************************************************/ /* 詞法分析片斷 */ /************************************************************************/ char *scanner(char ch) { token=(char *)malloc(15); *token = NULL; char chNext; /*剔除空白字符*/ while((ch ==' '|| ch == '\t')&&(ch != EOF)) { ch=fgetc(fp); } /************************************************************************/ /* 頭文件名、標識符或保留字 */ /************************************************************************/ //合法標識符一字母或下劃線打頭 if(letter(ch)||(ch=='_')) { while(letter(ch) || digit(ch)||(ch =='_')) { concatennation(ch); ch = fgetc(fp); } chNext = fgetc(fp); //頭文件 if ((ch=='.')&&( (chNext=='h')||(chNext=='c') )) { concatennation(ch); concatennation(chNext); buildlist(token,2); return token; } else { retract(fp,chNext); retract(fp,ch); if (reserve(token)) { //保留字 reserve(token); return token; } else {//標識符 buildlist(token,0); return token; } } } /************************************************************************/ /* 常數數字串 */ /************************************************************************/ else if(digit(ch)) { //數字串 int t = 0; while(digit(ch) || (ch == '.')) { // if ('.' == ch) { t ++ ; } concatennation(ch); ch = fgetc(fp); } retract(fp,ch); buildlist(token,1); if (0 == t) { NUM[numPoint-1].num_Type = "int"; } else if (1 == t) { NUM[numPoint-1].num_Type = "float"; } else { error(101,Line,"scanner error : Incrementimal point"); } return token; } /************************************************************************/ /* 運算符'+'系列 */ /************************************************************************/ else if(ch == '+') { chNext = fgetc(fp); if(chNext == '=') { //賦值運算符 return "+="; } else if(chNext == '+') { //自增運算符 return "++"; } else { //雙目運算符'+' retract(fp,chNext); return "+"; } } /************************************************************************/ /* 運算符'-'系列 */ /************************************************************************/ else if (ch == '-') { chNext = fgetc(fp); if (ch == '=') { //賦值運算符 return "-="; } else if(chNext == '-') { //自減運算符 return "--"; } else { //雙目運算符'-' retract(fp,chNext); return "-"; } } /************************************************************************/ /* 運算符'*'系列 */ /************************************************************************/ else if (ch == '*') { chNext = fgetc(fp); if(chNext == '=') { //賦值運算符 return "*="; } else { retract(fp,chNext);//雙目運算符'*' return "*"; } } /************************************************************************/ /* 運算符'/'及註釋系列 */ /************************************************************************/ else if (ch == '/') { chNext = fgetc(fp); if(chNext == '=') { //賦值運算符 return "/="; } else if(chNext == '/') { //單行註釋 ch = fgetc(fp); while (ch!='\n') { ch = fgetc(fp); } scanner(fgetc(fp)); } else if(chNext == '*') { char chh=' '; ch = fgetc(fp); while((chh!='*')&&(ch!='/')) { //多行註釋 chh = ch; ch = fgetc(fp); } scanner(fgetc(fp)); } else { //雙目運算符'/' retract(fp,chNext); return "/"; } } /************************************************************************/ /* 賦值運算符、等號 */ /************************************************************************/ else if(ch == '=') { chNext = fgetc(fp); if(chNext == '=') { //等號 return "=="; } else { //賦值號 retract(fp,chNext); return "="; } } /************************************************************************/ /* 小於及小於等於 */ /************************************************************************/ else if (ch == '<') { chNext = fgetc(fp); if(chNext == '=') { return "<="; } else { retract(fp,chNext); return "<"; } } /************************************************************************/ /* 大於及大於等於 */ /************************************************************************/ else if (ch == '>') { chNext = fgetc(fp); if(chNext == '=') { return ">="; } else { retract(fp,chNext); return ">"; } } else if (ch == '%') { return "%"; } /************************************************************************/ /* 界符'('、')'、'{'、'}'、'['、']'、'"'、'\''、','、';'等 */ /************************************************************************/ else if (ch == '(') { return "("; } else if (ch == ')') { return ")"; } else if (ch == '{') { return "{"; } else if (ch == '}') { return "}"; } else if (ch == '[') { return "["; } else if (ch == ']') { return "]"; } else if (ch == ',') { return ","; } else if (ch == ';') { return ";"; } else if (ch == '"') { return "\""; } else if (ch == '\'') { return "'"; } /************************************************************************/ /* 其餘字符 */ /************************************************************************/ else if (ch == '\n') { return "\n"; } else if (ch == '#') { return "#"; } else if (ch == '&') { return "&"; } else if (ch == '|') { return "|"; } else if (ch == '^') { return "^"; } else if (ch == '%') { return "%"; } else { error(100,Line,"scanner error : "); //scanner(fgetc(fp)); } return "chwen"; } /************************************************************************/ /* 語法分析部分 */ /************************************************************************/ void var_List(); //調用詞法分析器獲取一個單詞 char *getNext() { char ch; ch = fgetc(fp); while (ch != EOF) { token = scanner(ch);//獲取一個詞語 if (!strcmp(token,"\n")) { //若爲換行符則行數加加 Line++; getNext(); } return token; } return "chwen"; } //變量定義類型 是返回1,不然返回0 int Type(char *lookhead) { if(!strcmp(lookhead,"int")) { type = "int"; return 1; } else if (!strcmp(lookhead,"float")) { type = "float"; return 1; } else { return 0; } } //函數返回值類型 void re_Type(char*lookhead) { if (!strcmp(lookhead,"void")) { type = "void"; } else { Type(lookhead); } } //函數名 void myFunction_Name(char *lookhead) { for (int i=0;i<opPoint;i++) { if (!strcmp(lookhead,ID[i].id_Name)) { ID[i].id_Attrib = "hanshu"; ID[i].id_Beg = Line; ID[i].id_type = type; } } } //變量聲明 void id_name() { char *lookhead = getNext(); for (int i=0;i<opPoint;i++) { if (!strcmp(lookhead,ID[i].id_Name)) { if (i == opPoint-1) { ID[i].id_Attrib = "bianliang"; ID[i].id_Beg = Line; ID[i].id_type = type; } } } } //變量名 不合法返回-1 int id_name1(char*lookhead) { int flag = -1; for (int i=0;i<opPoint;i++) { if (!strcmp(lookhead,ID[i].id_Name)) { flag=i; if (ID[i].id_Beg == 0) { error(110,Line,"syntax error :variable unDeclareared identifier"); } } } return flag; } //變量長定義 void var_List1() { char *lookhead = getNext(); if (!strcmp(lookhead,",")) { var_List();// } else if (!strcmp(token,";")) { ; } else { error(111,Line,"syntax error : missing ';'"); } } //變量列表 void var_List() { id_name();// var_List1();// } //變量聲明 void Declare(char *lookhead) { Type(lookhead);// var_List(); // } //常數 不是常數返回 -1 int Const(char *lookhead) { int Flag = -1; for (int i=0;i<numPoint;i++) { if (!strcmp(lookhead,NUM[i].num)) { Flag = i; Valuei = atoi(lookhead); } } return Flag; } //運算符號 是返回1 不然返回0 int opChar(char *lookhead) { if (!strcmp(lookhead,"+") || !strcmp(lookhead,"-") || !strcmp(lookhead,"*") || !strcmp(lookhead,"/")) { return 1; } return 0; } void T(char*); //帶括號的表達式 void F(char*lookhead) { if (-1 != id_name1(lookhead)) { ; } else if(!strcmp(lookhead,"(")) { T(getNext()); if (strcmp(token,")")) { error(112,Line,"syntax error( : missing ')'"); } } else { error(113,Line,"syntax error( : missing ')'"); } } void T1() { char *lookhead = getNext(); if (opChar(lookhead)) { lookhead = getNext(); F(lookhead); T1();// } else if(!strcmp(lookhead,";")) { ; } else { error(145,Line,"syntax error : missing ';'"); } } //帶括號的加減乘除表達式 void T(char*lookhead) { F(lookhead);// T1();// } void Bdshi(char*lookhead) { T(lookhead);// } int test_id(char *lookhead) { int Flag = -1; for (int i=0;i<opPoint;i++) { //該str是否是合法標識符 if (!strcmp(lookhead,ID[i].id_Name) && (ID[i].id_Beg!=0)) { Flag = i; } } return Flag; } //賦值語句 void Fuzhi(char *lookhead,int Flag) { lookhead = getNext(); if (!strcmp(lookhead,"=")) { lookhead = getNext(); if (-1 != Const(lookhead)) { //將常量付給變量 ID[Flag].id_Valuei = Valuei; if(strcmp(getNext(),";")) { error(114,Line,"syntax error : missing ';'"); } } else { Bdshi(lookhead);//表達式付給變量 } } } //條件語句 void Condition() { char * lookhead = getNext(); if(!strcmp(lookhead,"true")||!strcmp(lookhead,"false")||!strcmp(lookhead,"0")||!strcmp(lookhead,"1")) { ; } else if(-1 != id_name1(lookhead)) { lookhead = getNext(); if( (!strcmp(lookhead,"<")) ||(!strcmp(lookhead,"<=")) ||(!strcmp(lookhead,">")) ||(!strcmp(lookhead,">=")) ||(!strcmp(lookhead,"==")) ||(!strcmp(lookhead,"!="))) { lookhead = getNext(); if(-1 == Const(lookhead)) { error(140,Line,"syntax error : ')'"); } } else { retract(fp,ch); } } else { error(141,Line,"syntax error : ')'"); } } //增量語句 void Increment() { char * lookhead = getNext(); if (-1 != id_name1(lookhead)) { lookhead = getNext(); if ((!strcmp(lookhead,"++"))||(!strcmp(lookhead,"--"))) { ; } else if((!strcmp(lookhead,"+=")) ||(!strcmp(lookhead,"-=")) ||(!strcmp(lookhead,"*=")) ||(!strcmp(lookhead,"/="))) { lookhead = getNext(); if(-1 == Const(lookhead)) { error(142,Line,"syntax error : ')'"); } } } else { retract(fp,ch); } } void myFunction(); //if 條件語句 void myIf() { char *lookhead = getNext(); if (!strcmp(lookhead,"(")) { Condition(); if (!strcmp(getNext(),")")) { if (!strcmp(getNext(),"{")) { myFunction(); retract(fp,ch); if (strcmp(getNext(),"}")) { error(116,Line,"fatal error : unexpected end of file found"); } } else { error(135,Line,"syntax error : missing ';' before '}'"); } } else { error(136,Line,"syntax error : missing ')' before '{'"); } } else { error(117,Line,"syntax error : missing ';' after 'if'"); } } //while 循環語句 void myWhile() { char *lookhead = getNext(); if (!strcmp(lookhead,"(")) { Condition(); if (!strcmp(getNext(),")")) { if (!strcmp(getNext(),"{")) { myFunction(); retract(fp,ch); if (strcmp(getNext(),"}")) { //改寫 error(116,Line,"fatal error : unexpected end of file found"); } } else { error(137,Line,"syntax error : missing ';' before '}'"); } } else { error(138,Line,"syntax error : missing ')' before '{'"); } } else { error(117,Line,"syntax error : missing ';' after 'while'"); } } //for 循環語句 void myFor() { int i=0; char * lookhead = getNext(); if (!strcmp(lookhead,"(")) { lookhead = getNext(); if (-1 != ( i=test_id(lookhead))) { //初值 Fuzhi(lookhead,i); } else { error(131,Line,"unDeclareared identifier"); } Condition();//條件 lookhead = getNext(); if (!strcmp(lookhead,";")) { Increment();//增量 lookhead = getNext(); if (!strcmp(lookhead,")")) { if (!strcmp(getNext(),"{")) { myFunction(); retract(fp,ch); if (strcmp(getNext(),"}")) { error(116,Line,"fatal error : unexpected end of file found"); } } else { error(134,Line,"syntax error : missing ';' before '}'"); } } else { error(133,Line,"syntax error : missing ')' before '{'"); } } else { error(130,Line,"not ';'"); } } } void myReturn () { char *lookhead = getNext(); if (!strcmp(lookhead,"0")) { lookhead = getNext(); if (strcmp(lookhead,";")) { error(151,Line,"syntax error : missing ';' before '}'"); } } else { error(150,Line,"function should return a value; 'void' return type assumed"); } } //函數體語句 void myFunction1(char *str) { int i = 0; if (Type(str)) { Declare(str); return; } else if (-1 != ( i=test_id(str))) { Fuzhi(str,i); return; } else if (!strcmp(str,"if")) { myIf(); return; } else if (!strcmp(str,"while")) { myWhile(); return; } else if (!strcmp(str,"for")) { myFor(); return; } else if (!strcmp(str,"return")) { myReturn(); return; } else { ; } } //函數體 void myFunction() { char *str = getNext(); while (strcmp(str,"}")) { myFunction1(str); str = getNext(); } } //參數表 void P() { ; } void headFile() { char *lookhead = getNext(); } //編譯預處理頭文件 void includ(char*lookhead) { if (!strcmp(lookhead,"#")) { if (!strcmp(getNext(),"include")) { if (!strcmp(getNext(),"<") ) { headFile();// if (strcmp(getNext(),">") ) { error(119,Line,"invalid preprocessor command"); } } else { error(120,Line,"invalid preprocessor command"); } } else { error(121,Line,"invalid preprocessor command"); } } else { error(122,Line,"syntax error : missing ';'"); } } //主函數語句 void myMain(char *lookhead) { re_Type(lookhead);//1 lookhead = getNext(); myFunction_Name(lookhead);//2 lookhead = getNext(); if(!strcmp(lookhead,"(")) { P(); if(!strcmp(getNext(),")")) { if(!strcmp( getNext(),"{")) { myFunction();// retract(fp,ch); lookhead = getNext(); if (!strcmp( lookhead,"}")) { ch = fgetc(fp); while (EOF != ch) { //處理結束符‘}’後還有其餘字符 if (!(ch==' ')&&!(ch=='\n')&&!(ch=='\t')) { error(143,Line,"syntax error : missing ';' before '}'"); } ch = fgetc(fp); } } else { error(123,Line,"fatal error : unexpected end of file found or missing '}'"); } } else { error(124,Line,"syntax error : missing '{'"); } } else { error(125,Line,"syntax error : missing ')'"); } } else { error(126,Line,"syntax error : missing '('"); } } //一簡單程序(頭文件、主函數) int S() { char*lookhead = ""; lookhead = getNext(); while (!strcmp(lookhead,"#")) { includ(lookhead); lookhead = getNext(); } myMain(lookhead); return err_count; } void tttt(int t) { for (int i=0;i<t;i++) { printf("\t"); } } //將源程序格式化輸出 void print() { fseek(fp,0,0);int tt = 0; ch = fgetc(fp); while(ch != EOF) { if(';'==ch) { putchar(ch); putchar('\n'); tttt(tt); } else if('\n'==ch) { ; } else if ('{'==ch) { tt++; putchar(ch); putchar('\n'); tttt(tt); } else if('}'==ch) { tt--; printf("\b\b\b\b\b\b\b\b"); putchar(ch); putchar('\n'); tttt(tt); } else if('>'==ch) { putchar(ch); putchar('\n'); } else if((' '==ch)||('\t'==ch)) { putchar(' '); while((' '==ch)||('\t'==ch)) { ch = fgetc(fp); } if(EOF!=ch) { retract(fp,ch); } else { break; } } else { putchar(ch); } ch = fgetc(fp); } } void Result() { if (!S()) { printf("\nThe source file: %d error(s)\n",err_count); print(); printf("\n The source file success!\n\n\n"); } else { printf("\n The source file:%d error(s)\n\n\n",err_count); } } /************************************************************************/ /* 主測試函數 */ /************************************************************************/ int main() { if((fp = fopen("003.txt","rt")) == NULL) { printf("cannot open the file!!\n"); exit(0); } Result(); fclose(fp); return 0; }