词法分析器(含完整源码)
编译原理词法分析器-ll1-lr0-python实现代码

编译原理词法分析器-ll1-lr0-python实现代码计算机科学与通信工程学院编译原理实验报告题目: 1.词法分析器2. LL(1)分析器3. LR(0)分析器班级:姓名:学号:指导老师:2017年月目录一、实验题目 (1)二、实验目的和要求 (1)三、代码实现 (2)四、总结 (25)一、实验题目1.词法分析器分析一段程序代码,将代码中的单词符号分解出来,并对其进行检查,输出token表和error表2.LL(1)文法分析器分析给定文法。
求出文法的FIRST集,FOLLOW集,并构建分析表,对给定输入串进行分析。
3.LR(0)文法分析器分析给定文法。
用Ꜫ_CLOSURE方法构造文法的LR(0)项目集规范族,根据状态转换函数GO构造出文法的DFA,并转换为分析表,对给定输入串进行分析。
二、实验目的和要求1.学会词法分析器的实现思路。
2.学会求解FIRST集, FOLLOW集,构造LL(1)分析表。
3.学会Ꜫ_CLOSURE方法,状态转换函数GO, 构造LR(0)分析表。
三、代码实现1.词法分析器program.txt 中存放要分析的文法:E->TRR->+TR|-TR|~T->FGG->*FG|/FG|~F->(E)|i代码:KEYWORD_LIST = ['while', 'if', 'else', 'switch', 'case']SEPARATOR_LIST = [';', ':', ',', '(', ')', '[', ']', '{', '}']OPERATOR_LIST1 = ['+', '-', '*']OPERATOR_LIST2 = ['<=', '<', '==', '=', '>', '>=']CATEGORY_DICT = {# KEYWORD"while": {"while": ""},"if": {"if": ""},"else": {"else": ""},"switch": {"switch": ""},"case": {"case": ""},# OPERATOR"+": {"+": ""},"-": {"-": ""},"*": {"*": ""},"<=": {"relop": "LE"},"<": {"relop": "LT"},">=": {"relop": "GE"},">": {"relop": "GT"},"==": {"relop": "EQ"},"=": {"=": ""},# SEPARATOR";": {";": ""},":": {":": ""},",": {",": ""},"(": {"(": ""},")": {")": ""},"[": {"]": ""},"]": {"]": ""},"{": {"{": ""},"}": {"}": ""},}CONSTANTTABLE = []TOKENTABLE = []OPERATORTABLE = []KEYWORDTABLE = []SEPARATORTABLE = []UNDEFINEDTABLE = []# READ FILEdef read_file(path, method):temp_str = ""try:file = open(path, method)for line in file:line = line.replace('\n', " ") temp_str += linetemp_str = str(temp_str)except IOError as e:print(e)exit()finally:file.close()return temp_str.strip() + " "# GETBEdef getbe():global tokengetchar()token = ""return# GETCHARdef getchar():global characterglobal locationwhile all_string[location] == " ":location = location + 1character = all_string[location]return character# LINK TOKENdef concatenation():global tokenglobal charactertoken = token + character# IS NUMBERdef digit():if '0' <= character <= '9':return Truereturn False# IS ALPHABETdef letter():if 'A' <= character <= 'Z' or 'a' <= character <= 'z': return Truereturn False# IS IDENTIFIERdef reserve():if token in KEYWORD_LIST:return CATEGORY_DICT[token]else:return 0# RETRACTdef retract():global locationglobal character# location = location - 1character = ""return# MAIN FUNCTIONdef main():global tokenglobal characters = getchar()getbe()if 'a' <= s <= 'z' or 'A' <= s <= 'Z':while letter() or digit():concatenation()location = location + 1character = all_string[location]retract()c = reserve()if c == 0:TOKENTABLE.append(token)print("这是标识符:{'", token, "':'", TOKENTABLE.index(token), "'}") else:KEYWORDTABLE.append(token)print("这是保留字:", CATEGORY_DICT[token])elif '0' <= s <= '9':while digit():concatenation()location = location + 1character = all_string[location]retract()CONSTANTTABLE.append(token)print("这是常数:{'", token, "':'", CONSTANTTABLE.index(token), "'}") elif s in OPERATOR_LIST1:location = location + 1OPERATORTABLE.append(s)print("这是单操作符:", CATEGORY_DICT[s])elif s in OPERATOR_LIST2:location = location + 1character = all_string[location]if character == '=':OPERATORTABLE.append(s + character)print("这是双操作符:", CATEGORY_DICT[s + character])else:retract()location = location + 1OPERATORTABLE.append(s)print("这是单操作符:", CATEGORY_DICT[s])elif s in SEPARATOR_LIST:location = location + 1SEPARATORTABLE.append(s)print("这是分隔符:", CATEGORY_DICT[s])else:UNDEFINEDTABLE.append(s)print("error:undefined identity :'", s, "'")if __name__ == '__main__':character = ""token = ""all_string = read_file("program.txt", "r")location = 0while location + 1 < len(all_string):main()print('KEYWORDTABLE:', KEYWORDTABLE)print('TOKENTABLE:', TOKENTABLE)print('CONSTANTTABLE:', CONSTANTTABLE)print('OPERATORTABLE:', OPERATORTABLE)print('SEPARATORTABLE:', SEPARATORTABLE)运行结果:2.LL(1)分析器program.txt 中存放要分析的文法:E->TRR->+TR|-TR|~T->FGG->*FG|/FG|~F->(E)|i输入串:i+i*i代码:NonTermSet = set() # 非终结符集合TermSet = set() # 终结符集合First = {} # First集Follow = {} # Follow集GramaDict = {} # 处理过的产生式Code = [] # 读入的产生式AnalysisList = {} # 分析表StartSym = "" # 开始符号EndSym = '#' # 结束符号为“#“Epsilon = "~" # 由于没有epsilon符号用“~”代替# 构造First集def getFirst():global NonTermSet, TermSet, First, Follow, FirstAfor X in NonTermSet:First[X] = set() # 初始化非终结符First集为空for X in TermSet:First[X] = set(X) # 初始化终结符First集为自己Change = Truewhile Change: # 当First集没有更新则算法结束Change = Falsefor X in NonTermSet:for Y in GramaDict[X]:k = 0Continue = Truewhile Continue and k < len(Y):if not First[Y[k]] - set(Epsilon) <= First[X]: # 没有一样的就添加,并且改变标志if Epsilon not in First[Y[k]] and Y[k] in NonTermSet and k > 0: # Y1到Yi候选式都有~存在Continue = Falseelse:First[X] |= First[Y[k]] - set(Epsilon)Change = Trueif Epsilon not in First[Y[k]]:Continue = Falsek += 1if Continue: # X->~或者Y1到Yk均有~产生式First[X] |= set(Epsilon)# FirstA[Y] |= set(Epsilon)# 构造Follow集def getFollow():global NonTermSet, TermSet, First, Follow, StartSymfor A in NonTermSet:Follow[A] = set()Follow[StartSym].add(EndSym) # 将结束符号加入Follow[开始符号]中Change = Truewhile Change: # 当Follow集没有更新算法结束Change = Falsefor X in NonTermSet:for Y in GramaDict[X]:for i in range(len(Y)):if Y[i] in TermSet:continueFlag = Truefor j in range(i + 1, len(Y)): # continueif not First[Y[j]] - set(Epsilon) <= Follow[Y[i]]:Follow[Y[i]] |= First[Y[j]] - set(Epsilon) # 步骤2 FIRST(β)/~ 加入到FOLLOW(B)中。
编译原理----词法分析程序----C语言版

编译原理----词法分析程序----C语⾔版#include<stdio.h>#include<string.h>#include<stdlib.h>char KeyWord[20][100]={"begin","end","if","while","var","procedure","else","for","do","int","read","write"};char yunsuanfu[]="+-*/<>%=";char fenjiefu[]=",;(){}:";int main(){char test[]="var a=10;\nvar b,c;\nprocedure p; \n\tbegin\n\t\tc=a+b\n\tend\n";int len_yunsuanfu=strlen(yunsuanfu);int len_fenjiefu=strlen(fenjiefu);puts(test);int length=strlen(test),i,j,k;for(i=0;i<length;i++){if(test[i]==' '||test[i]=='\n'||test[i]=='\t')continue;int tag=0;for(j=0;j<len_fenjiefu;j++){if(fenjiefu [j]==test[i]){printf("分界符\t%c\n",test[i]);tag=1;break;}}if(tag==1)continue;tag=0;for(j=0;j<len_yunsuanfu;j++){if(yunsuanfu[j]==test[i]){printf("运算符\t%c\n",test[i]);tag=1;break;}}if(tag==1)continue;if(test[i]>='0'&&test[i]<='9'){printf("数字\t");while(test[i]>='0'&&test[i]<='9'){printf("%c",test[i]);i++;}printf("\n");continue;}char temp[100];j=0;while(test[i]>='0'&&test[i]<='9'||test[i]>='a'&&test[i]<='z'||test[i]>='A'&&test[i]<='Z'||test[i]=='_') {temp[j++]=test[i];i++;}i--;temp[j++]='\0';tag=0;for(j=0;j<20;j++){if(strcmp(temp,KeyWord[j])==0){tag=1;printf("关键字\t%s\n",temp);break;}}if(tag==0)printf("标识符\t%s\n",temp);}}。
编译原理词法分析器代码

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <ctype.h>#include <conio.h>#define KEYWORD_LEN 32 //保留字个数#define STR_MAX_LEN 300 //标识符最大长度#define PRO_MAX_LEN 20480 //源程序最大长度#define STB_MAX_LEN 1000 //符号表最大容量#define CTB_MAX_LEN 1000 //常数表最大容量#define ERROR 0 //错误#define ID (KEYWORD_LEN+1) //标识符#define CONST (KEYWORD_LEN+2) //常量#define OPERAT (KEYWORD_LEN+3) //运算符#define DIVIDE (KEYWORD_LEN+4) //界符int errorLine=0; char proBuffer[PRO_MAX_LEN] = ""; //存储程序代码的全局缓冲区char ch; //读出来的当前字符char wordget[STR_MAX_LEN]; //标识符或常量int point = 0; //源程序当前位置指针char signTab[STB_MAX_LEN][STR_MAX_LEN]; //符号表int pointSTB = 0; //符号表指针char constTab[CTB_MAX_LEN][STR_MAX_LEN]; //常量表int pointCTB = 0; //常数表指针char kwTab[KEYWORD_LEN][10]={ //保留字表C语言一共有32个保留字[关键字]"auto", "break", "case", "char","const", "continue", "default","do", "double", "else", "enum","extern", "float", "for", "goto","if", "int", "long", "register","return", "short", "signed", "sizeof","static", "struct", "switch", "typedef","union", "unsigned", "void", "volatile", "while"};char errorTab[][50]={ //错误代码表/*0*/"未知错误", /*1*/"非法的字符", /*2*/"不正确的字符常量表达",/*3*/"不正确的字符串表达", /*4*/"不正确的数字表达", /*5*/"注释丢失'*/'"};typedef struct signDuality{int kind;int value;}*pDualistic, Dualistic;void pretreatment(); //预处理void ProcError(int id); //错误bool GetChar(); //获得一个字符不包括结束标记bool GetBC(); //获得一个非空白字符void Concat(char *str); //将ch连接到str后int Reserve(char *str); //对str字符串查找保留字表若是一个保留字-返回其编码否则返回0void Retract(); //将搜索指示器回调一个字符位置int InsertId(char *str);//将str串以标识符插入符号表,并返回符号表指针int InsertConst(char *str); //将str串以常数插入符号表,并返回常数表指针bool wordAnalyse(pDualistic pDu); //词法分析true正常//预处理将缓冲区内的源代码去掉注释和无效空格void pretreatment(){int lines=0;char tmp[PRO_MAX_LEN]; //先将处理结果保存到临时空间int tmpp = 0; //这个临时空间的末尾指针bool flg;char tmpc; //去掉注释先//注释有两种一种是// 另一种是/**/point = 0;do{flg = GetChar();if(ch == '/'){flg = GetChar();switch(ch){case '/':do{flg = GetChar();}while(!(ch == '\n' || flg == false));//注释一直到行尾或文件结束if(ch == '\n')Retract(); //归还换行break;case '*':do{flg = GetChar();tmpc = ch;//为了保证出错处理程序能正确定位出错位置保留注释中的换行if(tmpc == '\n')tmp[tmpp++] = tmpc;flg = GetChar();Retract(); //归还一个字符}while(flg && !(flg && tmpc == '*' && ch == '/'));flg = GetChar();if (!flg){ProcError(5);}break;default: //不是任何一种注释Retract();Retract();GetChar();tmp[tmpp++] = ch;flg = GetChar();tmp[tmpp++] = ch;}}else{tmp[tmpp++] = ch;}}while(flg);tmp[tmpp] = '\0';strcpy(proBuffer,tmp);}//错误void ProcError(int id){printf("\nError:第%d行,%s\n",errorLine, errorTab[id]);}//获得一个字符bool GetChar(){if(point < PRO_MAX_LEN && proBuffer[point] != '\0'){//如果当前下标合法且当前字符为结束标记则取字符增游标ch = proBuffer[point++];if (ch == '\n')errorLine ++;return true;}ch = '\0';return false;}//获得一个非空白字符bool GetBC(){do{if(!GetChar()) //获取字符失败{ch = '\0';return false;}}while(isspace(ch)); //直到获得一个非空白字符return true;}//将ch连接到str后void Concat(char *str){int i;for(i=0; str[i]; ++i);str[i] = ch;str[i+1] = '\0';}//对str字符串查找保留字表若是一个保留字-返回其编码否则返回0int Reserve(char *str){int i;for(i=0; i<KEYWORD_LEN; ++i) //从保留字表中查找str串{if(0 == strcmp(kwTab[i], str))return i+1; //注意,这里加一原因是0值被错误标记占用}return 0;}//将搜索指示器回调一个字符位置void Retract()///char *ch{if(proBuffer[point] == '\n' && errorLine > 0)errorLine --;point --;}//将str串以标识符插入符号表,并返回符号表指针int InsertId(char *str){int i;for(i=0; i < pointSTB; ++i)if(0 == strcmp(signTab[i], str))return i;strcpy(signTab[pointSTB++], str);return (pointSTB-1);}//将str串以常数插入常量表,并返回常数表指针int InsertConst(char *str){int i;for(i=0; i < pointCTB; ++i)if(0 == strcmp(constTab[i], str))return i;strcpy(constTab[pointCTB++], str);return (pointCTB-1);}//词法分析false--分析结束bool wordAnalyse(pDualistic pDu){int code, value;char judge; //这里有个技巧借用此变量巧妙的运用SWITCH结构int i = 0; //辅助GetBC();judge = ch;if (isalpha(ch) || ch == '_')judge='L';if (isdigit(ch))judge='D';switch(judge){case 'L':while(isalnum(ch) || ch == '_'){ //标识符wordget[i++] = ch;GetChar();}wordget[i] = '\0';Retract(); //回退一个字符code = Reserve(wordget);if(code == 0){value = InsertId(wordget);pDu->kind = ID;pDu->value = value;}else{pDu->kind = code;pDu->value = -1;}return true;case 'D':while(isdigit(ch)){wordget[i++] = ch;GetChar();}wordget[i] = '\0';Retract();value = InsertConst(wordget);pDu->kind = CONST;pDu->value= value;return true;//( ) [ ] . , ! != ~ sizeof < << <= > >> >= = == & && &= | || |= ?: + ++ +=// --> ---= * *= / /= % %= >>= <<= ^ ^=case '"': //字符串常量do{wordget[i++] = ch;GetChar();}while(ch != '"' && ch != '\0');wordget[i++] = ch;wordget[i] = '\0';if(ch == '\0'){printf("%s",wordget);ProcError(3);pDu->kind = ERROR;pDu->value = 0;}else{value = InsertConst(wordget);pDu->kind = CONST;pDu->value = value;}return true; //字符常量case '\'':wordget[i++] = ch; // 'GetChar();wordget[i++] = ch;if(ch == '\\') // '\n'{//如果是转义字符则要多接收一个字符GetChar(); // ch = 'wordget[i++] = ch;}GetChar();wordget[i++] = ch;wordget[i] = '\0';if(ch != '\''){//'\b'printf("%s",wordget);ProcError(2);pDu->kind = ERROR;pDu->value = 0;}else{value = InsertConst(wordget);pDu->kind = CONST;pDu->value = value;}return true;case '(':case ')':case '[':case ']':case '.':case ',':case '~':case '?':case ':':case ';':case '{':case '}':case '#':wordget[i++] = ch;wordget[i] = '\0';pDu->kind = DIVIDE; //界符pDu->value = -1;return true;case '!': //!=wordget[i++] = ch;GetChar();if (ch=='=')wordget[i++] = ch;elseRetract();wordget[i]='\0';break;case '<': // << <=wordget[i++] = ch;GetChar();if (ch == '<' || ch == '=')wordget[i++] = ch;elseRetract();wordget[i]='\0';break;case '>': // >> >=wordget[i++] = ch;GetChar();if (ch == '>' || ch == '=')wordget[i++] = ch;elseRetract();wordget[i]='\0';break;case '=': // ==wordget[i++] = ch;GetChar();if (ch == '=')wordget[i++] = ch;elseRetract();wordget[i]='\0';break;case '&': // && &=wordget[i++] = ch;GetChar();if (ch == '&' || ch == '=')wordget[i++] = ch;elseRetract();wordget[i]='\0';break; case '|': // || |=wordget[i++] = ch;GetChar();if (ch == '|' || ch == '=')wordget[i++] = ch;elseRetract();wordget[i]='\0';break;case '+': // ++ +=wordget[i++] = ch;GetChar();if (ch == '+' || ch == '=')wordget[i++] = ch;else Retract();wordget[i]='\0';break;case '-': // ---= ->wordget[i++] = ch;GetChar();if (ch == '-' || ch == '=' || ch == '>')wordget[i++] = ch;elseRetract();wordget[i]='\0';break;case '*':// ** *=wordget[i++] = ch;GetChar();if (ch == '*' || ch == '=')wordget[i++] = ch;elseRetract();wordget[i]='\0';break;case '/': // /=wordget[i++] = ch;GetChar();if (ch == '=')wordget[i++] = ch;elseRetract();wordget[i]='\0';break;case '%': // %=wordget[i++] = ch;GetChar();if (ch == '=')wordget[i++] = ch;elseRetract();wordget[i]='\0';break;case '^': // ^=wordget[i++] = ch;GetChar();if (ch == '=')wordget[i++] = ch;elseRetract();wordget[i]='\0';break;case '\0':return false;default:ProcError(1);return false;}pDu->kind = OPERAT;return true;}//主函数int main(){Dualistic tmp;pDualistic ptmp = &tmp;FILE *fin, *fout;int i;char c;char filename[20];printf("源代码读入\n");//scanf("%s",filename);//将源程序读入缓冲区if ((fin=fopen("Test.txt","r")) == NULL){printf("Cannot open infile\n");return 0;}i = 0;//c = fgetc(fin);while((c = fgetc(fin)) != EOF){if(i >= PRO_MAX_LEN-1){printf("\n程序代码太长,无法处理\a");return 0;}proBuffer[i++] = c;}fclose(fin); //关闭文件proBuffer[i++] = '\0';printf("\n***************************\n源代码读入成功,源代码如下:\n%s",proBuffer);printf("\n按任意键继续\n");getch(); //预处理printf("\n预处理\n");pretreatment();printf("\n***************************\n预处理成功,去掉注释后的源代码为:\n%s*",proBuffer);printf("\n按任意键继续\n");getch();printf("\n词法分析\n");point = 0;//词法分析if ((fout=fopen("Result.txt","wb")) == NULL){printf("建立文件Result.txt失败。
【编译原理】词法分析(CC++源代码+实验报告)

【编译原理】词法分析(CC++源代码+实验报告)⽂章⽬录1 实验⽬的和内容1.1实验⽬的(1)根据 PL/0 语⾔的⽂法规范,编写PL/0语⾔的词法分析程序;或者调研词法分析程序的⾃动⽣成⼯具LEX或FLEX,设计并实现⼀个能够输出单词序列的词法分析器。
(2)通过设计调试词法分析程序,实现从源程序中分离出各种类型的单词;加深对课堂教学的理解;提⾼词法分析⽅法的实践能⼒。
(3)掌握从源程序⽂件中读取有效字符的⽅法和产⽣源程序的内部表⽰⽂件的⽅法。
(4)掌握词法分析的实现⽅法。
(5)上机调试编出的词法分析程序。
1.2实验内容根据PL/0语⾔的⽂法规范,编写PL/0语⾔的词法分析程序。
要求:(1)把词法分析器设计成⼀个独⽴⼀遍的过程。
(2)词法分析器的输出形式采⽤⼆元式序列,即:(单词种类, 单词的值)2 设计思想2.1单词种类及其正规式(1)基本字单词的值单词类型正规式rbegin beginsym begincall callsym callconst constsym constdo dosym doend endsym endif ifsym ifodd oddsym oddprocedure proceduresym procedureread readsym readthen thensym thenvar varsym varwhile whilesym whilewrite writesym write(2)标识符单词的值单词类型正规式r标识符ident(字母)(字母|数字)*(3)常数单词的值单词类型正规式r常数number(数字)(数字)*(4)运算符单词的值单词类型正规式r+plus+-minus-*times*/slash/=eql=<>neq<><lss<<=leq<=>gtr>>=geq>=:=becomes:=(5)界符单词的值单词类型正规式r(lparen()rparen),comma,;semicolon;.period.2.2 根据正规式构造NFA下⾯我们根据上述的正规式来构造该⽂法的NFA,如下图所⽰,其中状态0为初态,凡带双圈的状态均为终态,状态24是识别不出单词符号的出错情形,其他状态的识别情况如下图中右边的注释所⽰。
基于LEX的C语言词法分析器

基于LEX的C语言词法分析器下面是一个基于LEX的C语言词法分析器的示例代码:```c#include <stdio.h>%}letter [a-zA-Z]digit [0-9]id {letter}({letter},{digit})*number {digit}+(\.{digit}+)?([eE][+-]?{digit}+)?%%{number} { printf("Number: %s\n", yytext); }{if} { printf("If: %s\n", yytext); }{else} { printf("Else: %s\n", yytext); }{while} { printf("While: %s\n", yytext); }{for} { printf("For: %s\n", yytext); }{id} { printf("Identifier: %s\n", yytext); }[ \t\n]+ // ignore white space. { printf("Unrecognized character: %c\n", yytext[0]); }%%int maiyylex(;return 0;```在上述代码中,首先是一些初始化的定义,定义了一些正则表达式模式,例如`letter`表示字母,`digit`表示数字,`id`表示标识符,`number`表示数字。
然后是各个模式的匹配规则和对应的处理逻辑。
其中,`{number}`表示如果匹配到了数字模式,就打印出该数字;`{if}`、`{else}`、`{while}`、`{for}`和`{id}`分别表示匹配到了if、else、while、for关键字和标识符,就打印出对应的信息;`[ \t\n]+`表示忽略空格和换行符;`.`表示匹配到了其他未定义的字符,就打印出异常信息。
(完整版)词法分析器(c语言实现)

词法分析c实现一、实验目的设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。
二、实验要求2.1 待分析的简单的词法(1)关键字:begin if then while do end所有的关键字都是小写。
(2)运算符和界符:= + - * / < <= <> > >= = ; ( ) #(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义:ID = letter (letter | digit)*NUM = digit digit*(4)空格有空白、制表符和换行符组成。
空格一般用来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略。
2.2 各种单词符号对应的种别码:输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。
其中:syn为单词种别码;token为存放的单词自身字符串;sum为整型常数。
例如:对源程序begin x:=9: if x>9 then x:=2*x+1/3; end #的源文件,经过词法分析后输出如下序列:(1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)……三、词法分析程序的C语言程序源代码:#include <stdio.h>#include <string.h>char prog[80],token[8],ch;int syn,p,m,n,sum;char *rwtab[6]={"begin","if","then","while","do","end"};scaner();main(){p=0;printf("\n please input a string(end with '#'):/n");do{scanf("%c",&ch);prog[p++]=ch;}while(ch!='#');p=0;do{scaner();switch(syn){case 11:printf("( %-10d%5d )\n",sum,syn);break;case -1:printf("you have input a wrong string\n");getch();exit(0);default: printf("( %-10s%5d )\n",token,syn);break;}}while(syn!=0);getch();}scaner(){ sum=0;for(m=0;m<8;m++)token[m++]=NULL;ch=prog[p++];m=0;while((ch==' ')||(ch=='\n'))ch=prog[p++];if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))){ while(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))||((ch>='0')&&(ch<='9'))) {token[m++]=ch;ch=prog[p++];}p--;syn=10;for(n=0;n<6;n++)if(strcmp(token,rwtab[n])==0){ syn=n+1;break;}}else if((ch>='0')&&(ch<='9')) { while((ch>='0')&&(ch<='9')) { sum=sum*10+ch-'0';ch=prog[p++];}p--;syn=11;}else switch(ch){ case '<':token[m++]=ch;ch=prog[p++];if(ch=='='){ syn=22;token[m++]=ch;}else{ syn=20;p--;}break;case '>':token[m++]=ch;ch=prog[p++];if(ch=='='){ syn=24;token[m++]=ch;}else{ syn=23;p--;}break;case '+': token[m++]=ch;ch=prog[p++];if(ch=='+'){ syn=17;token[m++]=ch;}else{ syn=13;p--;}break;ch=prog[p++];if(ch=='-'){ syn=29;token[m++]=ch;}else{ syn=14;p--;}break;case '!':ch=prog[p++];if(ch=='='){ syn=21;token[m++]=ch;}else{ syn=31;p--;}break;case '=':token[m++]=ch;ch=prog[p++];if(ch=='='){ syn=25;token[m++]=ch;}else{ syn=18;p--;}break;case '*': syn=15;token[m++]=ch;break;case '/': syn=16;token[m++]=ch;break;case '(': syn=27;token[m++]=ch;break;case ')': syn=28;break;case '{': syn=5;token[m++]=ch;break;case '}': syn=6;token[m++]=ch;break;case ';': syn=26;token[m++]=ch;break;case '\"': syn=30;token[m++]=ch;break;case '#': syn=0;token[m++]=ch;break;case ':':syn=17;token[m++]=ch;break;default: syn=-1;break;}token[m++]='\0';}四、结果分析:输入begin x:=9: if x>9 then x:=2*x+1/3; end # 后经词法分析输出如下序列:(begin 1)(x 10)(:17)(= 18)(9 11)(;26)(if 2)……如图5-1所示:。
词法分析器源代码

词法分析器源代码#include <iostream> #include <vector> #include <string> #include<fstream>/*单词种别码*/#define _CHAR 1 #define _INT 2#define _SHORT 3 #define _LONG 4 #define _SIGNED 5 #define _UNSIGNED 6 #define _FLOAT 7 #define _DOUBLE 8 #define _CONST 9 #define _VOID 10 #define _VOLATILE 11 #define _ENUM 12 #define _STRUCT 13 #define _UNION 14 #define _TYPEDEF 15 #define _AUTO 16 #define _EXTERN 17 #define_STATIC 18 #define _REGISTER 19 #define _IF 20#define _ELSE 21 #define _SWITCH 22 #define _CASE 23 #define_DEFAULT 24 #define _WHILE 25 #define _DO 26#define _FOR 27 #define _BREAK 28 #define _CONTINUE 29 #define _GOTO 30 #define _RETURN 31 #define _SIZEOF 32 #define _INCLUDE 33 #define_DEFINE 34 /*以上为关键字的种别码*/#define _ID 40 //标识符#define _NUM 50 //数#define _AS 51 //= #define _PLUS 52 //+ #define _SUB 53 //- #define _TIMES 54 // * #define _DIV 55 // / #define _LP 56 // ( #define _RP 57 // ) #define _LB1 58 // [ #define _RB1 59 // ] #define _LB2 60 //{ #define _RB2 61 // } #define _COM 62 // , #define _COL 63 // : #define_SEM 64 // #define _POINT 65 // . #define _LG 66 // > #define _LT 67 // < #define _ME 68 // >= #define _LE 69 // <= #define _EQ 70 // == #define _NE 71 // != #define _A 72 // >> #define _B 73 // >>= #define _C 74 // << #define _D 75 // <<= #define _E 76 // & #define _F 76 // && #define _G 77 // &= #define _H 78 // | #define _I 79 // || #define _J 80 // |= #define _K 81 // ~ #define _L 82 // ++ #define _M 83 // -- #define _N 84 // -> #define _O 85 // += #define _P 86 // -= #define _Q 87 // *=#define _R 88 // /= #define _S 89 // %=#define _T 90 // ^=#define _U 91 // %#define _V 92 // "#define _W 93 // '#define _X 94 // ?#define _EROOR -1 // 错误using namespace std;int ERROR_NUM=0; //记载词法编译错误个数bool isnum(string str) //判断是不是合法的数字{int y;int i;int j=0;int k=0;for(i=0;i<str.size();i++){if(!(str[i]<='9'&&str[i]>='0')){k++;if((k-j)>1){cout<<"数字串"<<str<<"出现词法错误~"<<endl;return false;} if(str[i]=='.') {j++;if(j>1) {cout<<"数字串"<<str<<"出现词法错误~"<<endl;return false;} }else if((str[i]=='E'||str[i]=='e')&&(str[i-1]<='9'&&str[i-1]>='0')&&((str[i+1]<='9'&&str[i+1]>='0')||(y=i+1)==str.size())) continue;else{cout<<"数字串"<<str<<"出现词法错误~"<<endl;return false;} }}return true;}/*该函数用来略过空格和换行符,找到有效字符的位置第一个参数为目标字符串,第二个参数为开始位置返回值为连续的空格和换行后的第一个有效字符在字符串的位置*/int valuable(string str,int i) {while(true){if(str[i]!=' '&&str[i]!='\n')return i;i++;}}int isexp(string str,int i) {if(str[i]=='/'&&str[i+1]=='/'){while(str[i]!='\n'){i++;}}return i;}int iskey(string str) //判断是不是关键字{stringp[34]={"char","int","short","long","signed","unsigned","float","double", "const","void","volatile","enum","struct","union","typedef","auto"," extern","static","register","if","else","switch","case","default","while","do", "for","break","continue","goto","return","size of","#include","#define"};vector<string> ppp(p,p+34); int u;for(u=0;u<ppp.size();u++)if(!pare(ppp[u]))return u+1;return 0;}vector<pair<int,string> > scan(vector<string> vec)//本次程序的主要分析程序 {vector<pair<int,string> > temp;int i;for(i=0;i<vec.size();i++){if(vec[i].size()==1){if(vec[i]==">"){if(vec[i+1]=="="){string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_ME,jk);temp.push_back(pp);continue;}else if(vec[i+1]==">"&&vec[i+2]!="=") { string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_A,jk);temp.push_back(pp);continue; }else if(vec[i+1]==">"&&vec[i+2]=="="){ string jk=vec[i];jk.append(vec[++i],0,1);jk.append(vec[++i],0,1);pair<int,string> pp(_B,jk);temp.push_back(pp);continue;}else {pair<int,string> pp(_LG,vec[i]);//标识符temp.push_back(pp);}}else if(vec[i]=="<") {if(vec[i+1]=="=") {string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_LE,jk);temp.push_back(pp);continue; }else if(vec[i+1]=="<"&&vec[i+2]!="=") { string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_C,jk);temp.push_back(pp);continue;}else if(vec[i+1]=="<"&&vec[i+2]=="=") { string jk=vec[i];jk.append(vec[++i],0,1);jk.append(vec[++i],0,1);pair<int,string> pp(_D,jk);temp.push_back(pp);continue; }else {pair<int,string> pp(_LT,vec[i]);//标识符temp.push_back(pp);}}else if(vec[i]=="!") {if(vec[i+1]=="=") {string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_LE,jk);temp.push_back(pp);continue;}else {pair<int,string> pp(_NE,vec[i]);//标识符temp.push_back(pp);}else if(vec[i]=="=") {if(vec[i+1]=="="){string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_EQ,jk);temp.push_back(pp);continue; }else {pair<int,string> pp(_AS,vec[i]);//标识符temp.push_back(pp); }}else if(vec[i]=="&") {if(vec[i+1]=="&") {string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_F,jk);temp.push_back(pp);continue;}else if(vec[i+1]=="=") {string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_G,jk);temp.push_back(pp);continue;}else {pair<int,string> pp(_E,vec[i]);//标识符temp.push_back(pp);}}else if(vec[i]=="|"){if(vec[i+1]=="|") {string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_I,jk);temp.push_back(pp);continue;}else if(vec[i+1]=="="){string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_J,jk);temp.push_back(pp);continue;}else {pair<int,string> pp(_H,vec[i]);//标识符temp.push_back(pp);}}else if(vec[i]=="(") {{pair<int,string> pp(_LP,vec[i]);//标识符temp.push_back(pp);}}else if(vec[i]==")"){{pair<int,string> pp(_RP,vec[i]);//标识符temp.push_back(pp); }}else if(vec[i]=="["){{pair<int,string> pp(_LB1,vec[i]);//标识符temp.push_back(pp); } }else if(vec[i]=="]") {{pair<int,string> pp(_RB1,vec[i]);//标识符temp.push_back(pp); } }else if(vec[i]=="~") {{pair<int,string> pp(_K,vec[i]);//标识符temp.push_back(pp); } }else if(vec[i]==",") {{pair<int,string> pp(_COM,vec[i]);//标识符temp.push_back(pp); } }else if(vec[i]=="{") {{pair<int,string> pp(_LB2,vec[i]);//标识符temp.push_back(pp);} }else if(vec[i]==":") {{pair<int,string> pp(_COL,vec[i]);//标识符temp.push_back(pp); } }else if(vec[i]==";") {{pair<int,string> pp(_SEM,vec[i]);//标识符temp.push_back(pp); } }else if(vec[i]=="}") {{pair<int,string> pp(_RB2,vec[i]);//标识符temp.push_back(pp); } }else if(vec[i]=="*") {if(vec[i+1]=="="){string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_Q,jk);temp.push_back(pp);continue; }else {pair<int,string> pp(_TIMES,vec[i]);//标识符temp.push_back(pp); } }else if(vec[i]=="/") {if(vec[i+1]=="=") {string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_R,jk);temp.push_back(pp);continue; }else if(vec[i+1]=="*") {i=i+4;while(i<vec.size()&&(vec[i-1]!="*"||vec[i]!="/"))i++; cont inue; }else {pair<int,string> pp(_DIV,vec[i]);//标识符temp.push_back(pp); }}else if(vec[i]=="%") {if(vec[i+1]=="=") {string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_S,jk);temp.push_back(pp);continue; }else {pair<int,string> pp(_U,vec[i]);//标识符temp.push_back(pp); } }else if(vec[i][0]=='"') {pair<int,string> pp(_V,vec[i]);//标识符temp.push_back(pp);}else if(vec[i][0]=='\'') {pair<int,string> pp(_W,vec[i]);//标识符temp.push_back(pp);}else if(vec[i][0]=='?'){pair<int,string> pp(_X,vec[i]);//标识符temp.push_back(pp); }else if(vec[i]=="+") {if(vec[i+1]=="=") {string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_O,jk);temp.push_back(pp);continue; }else if(vec[i+1]=="+") {string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_L,jk);temp.push_back(pp);continue; }else if((vec[i-1]=="="||vec[i-1]=="(")&&isnum(vec[i+1])) {string jk=vec[i]; jk.append(vec[++i]);pair<int,string> pp(_NUM,jk);temp.push_back(pp);continue; }else{pair<int,string> pp(_PLUS,vec[i]);//标识符temp.push_back(pp); } }else if(vec[i]=="-"){if(vec[i+1]=="=") {string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_P,jk);temp.push_back(pp);continue;}else if(vec[i+1]=="-") {string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_M,jk);temp.push_back(pp);continue; }else if(vec[i+1]==">") {string jk=vec[i];jk.append(vec[++i],0,1);pair<int,string> pp(_N,jk);temp.push_back(pp);continue;} else if((vec[i-1]=="="||vec[i-1]=="(")&&isnum(vec[i+1])) { string jk=vec[i]; jk.append(vec[++i]);pair<int,string> pp(_NUM,jk);temp.push_back(pp);continue; }else {pair<int,string> pp(_SUB,vec[i]);//标识符temp.push_back(pp);}}else if(vec[i][0]<='9'&&vec[i][0]>='0'){pair<int,string> pp(_NUM,vec[i]);temp.push_back(pp);}else{pair<int,string> pp(_ID,vec[i]);//标识符temp.push_back(pp);}}else if((vec[i][0]<='9'&&vec[i][0]>='0')||vec[i][0]=='.'){if(!isnum(vec[i]))ERROR_NUM++;else if((vec[i+1][0]=='+'||vec[i+1][0]=='-')&&isnum(vec[i+2])) { string jk=vec[i];jk.append(vec[++i]);jk.append(vec[++i]);pair<int,string> pp(_NUM,jk);temp.push_back(pp);continue;}else{pair<int,string> pp(_NUM,vec[i]);temp.push_back(pp);}}else if(iskey(vec[i])){pair<int,string> pp(iskey(vec[i]),vec[i]);temp.push_back(pp);}else{pair<int,string> pp(_ID,vec[i]);temp.push_back(pp);}}return temp;}void OutFile(vector<pair<int,string> > v) {int i;for(i=0;i<v.size();i++)outfile<<"<"<<v[i].first<<" , \""<<v[i].second<<"\">"<<endl; return;}。
实验一、词法分析器(含源代码)

词法分析器实验报告一、实验目的及要求本次实验通过用C语言设计、编制、调试一个词法分析子程序,识别单词,实现一个C语言词法分析器,经过此过程可以加深对编译器解析单词流的过程的了解。
运行环境:硬件:windows xp软件:visual c++6.0二、实验步骤1.查询资料,了解词法分析器的工作过程与原理。
2.分析题目,整理出基本设计思路。
3.实践编码,将设计思想转换用c语言编码实现,编译运行。
4.测试功能,多次设置包含不同字符,关键字的待解析文件,仔细察看运行结果,检测该分析器的分析结果是否正确。
通过最终的测试发现问题,逐渐完善代码中设置的分析对象与关键字表,拓宽分析范围提高分析能力。
三、实验内容本实验中将c语言单词符号分成了四类:关键字key(特别的将main说明为主函数)、普通标示符、常数和界符。
将关键字初始化在一个字符型指针数组*key[]中,将界符分别由程序中的case列出。
在词法分析过程中,关键字表和case列出的界符的内容是固定不变的(由程序中的初始化确定),因此,从源文件字符串中识别出现的关键字,界符只能从其中选取。
标识符、常数是在分析过程中不断形成的。
对于一个具体源程序而言,在扫描字符串时识别出一个单词,若这个单词的类型是关键字、普通标示符、常数或界符中之一,那么就将此单词以文字说明的形式输出.每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直到整个源程序全部扫描完毕,从而形成相应的单词串。
输出形式例如:void $关键字流程图、程序流程图:程序:#include<string.h>#include<stdio.h>#include<stdlib.h>#include<ctype.h>//定义关键字char*Key[10]={"main","void","int","char","printf","scanf","else","if","return"}; char Word[20],ch; // 存储识别出的单词流int IsAlpha(char c) { //判断是否为字母if(((c<='z')&&(c>='a'))||((c<='Z')&&(c>='A'))) return 1;else return 0;}int IsNum(char c){ //判断是否为数字if(c>='0'&&c<='9') return 1;else return 0;}int IsKey(char *Word){ //识别关键字函数int m,i;for(i=0;i<9;i++){if((m=strcmp(Word,Key[i]))==0){if(i==0)return 2;return 1;}}return 0;}void scanner(FILE *fp){ //扫描函数char Word[20]={'\0'};char ch;int i,c;ch=fgetc(fp); //获取字符,指针fp并自动指向下一个字符if(IsAlpha(ch)){ //判断该字符是否是字母Word[0]=ch;ch=fgetc(fp);i=1;while(IsNum(ch)||IsAlpha(ch)){ //判断该字符是否是字母或数字Word[i]=ch;i++;ch=fgetc(fp);}Word[i]='\0'; //'\0' 代表字符结束(空格)fseek(fp,-1,1); //回退一个字符c=IsKey(Word); //判断是否是关键字if(c==0) printf("%s\t$普通标识符\n\n",Word);//不是关键字else if(c==2) printf("%s\t$主函数\n\n",Word);else printf("%s\t$关键字\n\n",Word); //输出关键字 }else //开始判断的字符不是字母if(IsNum(ch)){ //判断是否是数字Word[0]=ch;ch=fgetc(fp);i=1;while(IsNum(ch)){Word[i]=ch;i++;ch=fgetc(fp);}Word[i]='\0';fseek(fp,-1,1); //回退printf("%s\t$无符号实数\n\n",Word);}else //开始判断的字符不是字母也不是数字{Word[0]=ch;switch(ch){case'[':case']':case'(':case')':case'{':case'}':case',':case'"':case';':printf("%s\t$界符\n\n",Word); break;case'+':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word);//运算符“+=”}else if(ch=='+'){printf("%s\t$运算符\n\n",Word); //判断结果为“++”}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word); //判断结果为“+”}break;case'-':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word); }else if(ch=='-'){printf("%s\t$运算符\n\n",Word); //判断结果为“--”}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word); //判断结果为“-”}break;case'*':case'/':case'!':case'=':ch=fgetc(fp);if(ch=='='){printf("%s\t$运算符\n\n",Word);}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word);}break;case'<':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word); //判断结果为运算符“<=”}else if(ch=='<'){printf("%s\t$运算符\n\n",Word); //判断结果为“<<”}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word); //判断结果为“<”}break;case'>':ch=fgetc(fp);Word[1]=ch;if(ch=='=') printf("%s\t$运算符\n\n",Word);else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word);}break;case'%':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word);}if(IsAlpha(ch)) printf("%s\t$类型标识符\n\n",Word);else {fseek(fp,-1,1);printf("%s\t$取余运算符\n\n",Word);}break;default:printf("无法识别字符!\n\n"); break;}}}main(){char in_fn[30]; //文件路径FILE *fp;printf("\n请输入源文件名(包括路径和后缀名):");while(1){gets(in_fn);//scanf("%s",in_fn);if((fp=fopen(in_fn,"r"))!=NULL) break; //读取文件内容,并返回文件指针,该指针指向文件的第一个字符else printf("文件路径错误!请重新输入:");}printf("\n******************* 词法分析结果如下 *******************\n");do{ch=fgetc(fp);if(ch=='#') break; //文件以#结尾,作为扫描结束条件else if(ch==' '||ch=='\t'||ch=='\n'){} //忽略空格,空白,和换行else{fseek(fp,-1,1); //回退一个字节开始识别单词流scanner(fp);}}while(ch!='#');return(0);}4.实验结果解析源文件:void main(){int a=3;a+=b;printf("%d",a);return;}#解析结果:5.实验总结分析通过本次实验,让再次浏览了有关c语言的一些基本知识,特别是对文件,字符串进行基本操作的方法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
词法分析实验报告一、实验目的与要求:1、了解字符串编码组成的词的涵,感觉一下字符串编码的方法和解读2、了解和掌握自动机理论和正规式理论在词法分析程序和控制理论中的应用二、实验容:构造一个自己设计的小语言的词法分析器:1、这个小语言能说明一些简单的变量识别诸如begin,end,if,while等保留字;识别非保留字的一般标识符(有下划线、字符、数字,且第一个字符不能是数字)。
识别数字序列(整数和小数);识别:=,<=,>=之类的特殊符号以及;,(,)等界符。
2、相关过程(函数):Scanner()词法扫描程序,提取标识符并填入display表中3、这个小语言有顺序结构的语句4、这个小语言能表达分支结构的语句5、这个小语言能够输出结果总之这个小语言词法分析器能提供以上所说明到的语法描述的功能……三、实验步骤:1、测试评价(1)、测试1:能说明一些简单的变量,如关键字、一般标识符、界符等;(2)、测试2:能输出结果:单词符号(码形式)、各种信息表(如符号表、常量表等);(3)、测试程序:var x,y,z;beginx:=2;y:=3;if (x+5>=y*y) thenbeginz:=y*y-x;z:=z+x*x;endelsez:=x+y;prn z;end.(4)、结果:①、从键盘读入;部分结果如下:(类型:该标识符所属的类型,如关键字,变量等;下标:该标识符所对应表(如变量标识符表,常量标识符表等)中其相应的位置,下同)②、从文件读入,输出到文件;部分结果如下:其他测试及结果如下:③、出错处理;注:若有错误,则只指出错误,不输出各个表;(5)、评价:这个小语言程序基本上能完成词法分析阶段的工作,识别诸如begin,if等保留字;识别非保留字的一般标识符(有下划线、字符、数字,且第一个字符不能是数字)。
识别数字序列(整数和小数);识别:=,<=,>=之类的特殊符号以及;,(,)等界符。
在扫描源程序串的同时,能进行一些简单的处理,如删除空格、tab、换行等无效字符,也进行了一些基本的错误处理,如变量长度的判别等。
遇到的问题:(a)、判别标识符超过规定长度(20)时,未输出处理结果;(b)、整数长度过长输出结果仍为整数类型3;(c)、对于小数如﹒045,被解释为界符和整数;(d)、对以数字开头的一般标识符的处理,如100nuts被解释为整数类型和标识符,未给出错误提示。
如上测试,出现前两个问题时已报错并输出所在行,而后两个问题待解决。
2、对小语言的词法规则(正规式)画出一个确定的有限自动机(见附录2、3)四、实验的源代码:(见附录1)五、实验中发现的问题和遇到的困难及解决方法:由于以前未曾接触过编译原理,在该实验的设计中,的确遇到一定的困难。
主要是display表结构的设计,由于语法分析和语义分析还未学习,无法站在全局的角度统筹兼顾,在表结构设计时,不知该往表结构体中添加哪些容,可以为后续的工作做铺垫,这是刚开始就遇到的最大的困难,也是最难的。
经过分析,我们在现有局限性的基础上,设计出一种折中的表结构,即在表结构中只添加标识符在其相应表中的对应下表,标记符类型码等关键的几处,这样既能唯一确定一标识符,达到该实验的要求,同时又为表保留了很好的扩充性,以达到后续实验的要求。
表结构设计好后,其余的工作就是提取字符串和写入display表,在提取单字符还是双字符组成的运算符时有些麻烦,不过利用数据结构的相关知识也是容易做到。
六、总结:词法分析是构造编译器的起始阶段,也是相应比较简单的一个环节。
词法分析的主要任务是:根据构造的状态转换图,从左到右逐个字符地対源程序进行扫描,识别开源程序中具有独立含义的最小语法单位——符号或单词,如变量标识符,关键字,常量,运算符,界符等。
然后将提取出的标识符以码的形式表示,即用int类型的数字来表示其类型和在display表中的位置,而无须保留原来标识符本身的字符串,这不仅节省了存空间,也有利于下一阶段的分析工作。
当然,在扫描源程序串的同时,进行一些简单的处理,如删除空格、tab、换行等无效字符,也进行了一些基本的错误处理,如变量长度的判别,有些不合词法规则的标识符判别等。
总之,严格说来,词法分析程序只进行和词法分析相关的工作。
七、实验感想:通过此次实验,让我了解到如何设计、编制并调试词法分析程序,加深对词法分析原理的理解;熟悉了构造词法分析程序的手工方式的相关原理,使用某种高级语言(例如C++语言)直接编写此法分析程序。
另外,也让我重新熟悉了C++语言的相关容,加深了对C++语言的用途的理解。
附录1(代码)#include <iostream>#include <fstream>#include <string>#include <math.h>#include <ctype.h>#include <cstdlib>using namespace std;#define Max 655 //最大代码长度#define WordMaxNum 256 //变量最大个数#define DigitNum 256 //常量最大个数#define MaxKeyWord 32 //关键字数量#define MaxOptANum 8 //运算符最大个数#define MaxOptBNum 4 //运算符最大个数#define MaxEndNum 11 //界符最大个数typedef struct DisplayTable{int Index; //标识符所在表的下标int type; //标识符的类型int line; //标识符所在表的行数char symbol[20]; //标识符所在表的名称}Table;int TableNum = 0; //display表的下标char Word[WordMaxNum][20]; //标识符表char Digit[WordMaxNum][20]; //数字表int WordNum = 0; //变量表的下标int DigNum = 0; //常量表的下标bool errorFlag = 0; //错误标志const char* const KeyWord[MaxKeyWord] = {"and", "array", "begin", "case","char""constant", "do", "else", "end", "false","for", "if", "input", "integer", "not", "of", "or", "output","packed","procedure", "program", "read", "real","repeat", "set", "then", "to", "type", "until", "var","while", "with","prn"}; //关键字const char OptA[] = {'+','-','*','/','=','#','<','>'}; // 单目运算const char *OptB[] = {"<=",">=",":=","<>"}; //双目运算符const char End[] = {'(', ')' , ',' , ';' , '.' , '[' , ']' , ':' , '{' , '}' , '"'}; // 界符void error(char str[20],int nLine, int errorType){cout <<" \nError : ";switch(errorType){case 1:cout << "第" << nLine-1 <<"行" << str << " 变量的长度超过限制!\n";errorFlag = 1;break;case 2:cout << "第" << nLine-1 <<"行" << str << " 小数点错误!\n";errorFlag = 1;break;case 3:cout << "第" << nLine-1 <<"行" << str << " 常量的长度超过限制!\n";errorFlag = 1;break;}}//errorvoid Scanner(char ch[],int chLen,Table table[Max],int nLine){int chIndex = 0;while(chIndex < chLen) //对输入的字符扫描{/**************************处理空格和tab ************************/ while(ch[chIndex] == ' ' || ch[chIndex] == 9 ) //忽略空格和tab{ chIndex ++; }/***************************处理换行符*************************************/ while(ch[chIndex] == 10) //遇到换行符,行数加1{ nLine++;chIndex ++;}/***************************标识符***************************************/ if( isalpha(ch[chIndex])) //以字母、下划线开头{char str[256];int strLen = 0;while(isalpha(ch[chIndex]) || ch[chIndex] == '_' ) //是字母、下划线{str[strLen ++] = ch[chIndex];chIndex ++;while(isdigit(ch[chIndex]))//不是第一位,可以为数字{str[strLen ++] = ch[chIndex];chIndex ++;}}str[strLen] = 0; //字符串结束符if(strlen(str) > 20) //标识符超过规定长度,报错处理{error(str,nLine,1);}else{ int i;for(i = 0;i < MaxKeyWord; i++) //与关键字匹配if(strcmp(str, KeyWord[i]) == 0) //是关键字,写入table表中{strcpy(table[TableNum].symbol,str);table[TableNum].type = 1; //关键字table[TableNum].line = nLine;table[TableNum].Index = i;TableNum ++;break;}if(i >= MaxKeyWord) //不是关键字{table[TableNum].Index = WordNum;strcpy(Word[WordNum++],str);table[TableNum].type = 2; //变量标识符strcpy(table[TableNum].symbol,str);table[TableNum].line = nLine;TableNum ++;}}}/**********************************常数***********************///else if(isdigit(ch[chIndex])&&ch[chIndex]!='0') //遇到数字else if(isdigit(ch[chIndex])) //遇到数字{int flag = 0;char str[256];int strLen = 0;while(isdigit(ch[chIndex]) || ch[chIndex] == '.') //数字和小数点{if(ch[chIndex] == '.') //flag表记小数点的个数,0时为整数,1时为小数,2时出错flag ++;str[strLen ++] = ch[chIndex];chIndex ++;}str[strLen] = 0;if(strlen(str) > 20) //常量标识符超过规定长度20,报错处理{error(str,nLine,3);}if(flag == 0){table[TableNum].type = 3; //整数}if(flag == 1){table[TableNum].type = 4; //小数}if(flag > 1){error(str,nLine,2);}table[TableNum].Index = DigNum;strcpy(Digit[DigNum ++],str);strcpy(table[TableNum].symbol,str);table[TableNum].line = nLine;TableNum ++;}/*******************************运算符************************************/else{int errorFlag; //用来区分是不是无法识别的标识符,0为运算符,1为界符char str[3];str[0] = ch[chIndex];str[1] = ch[chIndex + 1];str[3] = 0;for(int i = 0;i < MaxOptBNum;i++)//MaxOptBNum)if(strcmp(str,OptB[i]) == 0){errorFlag = 0;table[TableNum].type = 6;strcpy(table[TableNum].symbol,str);table[TableNum].line = nLine;table[TableNum].Index = i;TableNum ++;chIndex = chIndex + 2;break;}if(i >= MaxOptBNum){for( int k = 0;k < MaxOptANum; k++)if(OptA[k] == ch[chIndex]){errorFlag = 0;table[TableNum].type = 5;table[TableNum].symbol[0] = ch[chIndex];table[TableNum].symbol[1] = 0;table[TableNum].line = nLine;table[TableNum].Index = k;TableNum ++;chIndex ++;break;}/*************************界符*****************************************/ for(int j = 0;j < MaxEndNum;j ++)if(End[j] ==ch[chIndex]){errorFlag = 1;table[TableNum].line = nLine;table[TableNum].symbol[0] = ch[chIndex];table[TableNum].symbol[1] = 0;table[TableNum].Index = j;table[TableNum].type = 7;TableNum ++;chIndex ++;}/********************其他无法识别字符*************************************/ if(errorFlag != 0 && errorFlag != 1) //开头的不是字母、数字、运算符、界符{char str[256];int strLen = -1;str[strLen ++] = ch[chIndex];chIndex ++;while(*ch != ' ' || *ch != 9 || ch[chIndex] != 10)//{str[strLen ++] = ch[chIndex];chIndex ++;}str[strLen] = 0;table[TableNum].type = 8;strcpy(table[TableNum].symbol,str);table[TableNum].line = nLine;table[TableNum].Index = -2;TableNum ++;}}}}}void Trans(double x,int p) //把十进制小数转为16进制{int i=0; //控制保留的有效位数while(i<p){if(x==0) //如果小数部分是0break; //则退出循环else{int k=int(x*16); //取整数部分x=x*16-int(k); //得到小数部分if(k<=9)cout<<k;elsecout<<char(k+55);};i++;};};int main(){ifstream in;ofstream out,outVar,outCon;char in_file_name[26],out_file_name[26]; //读入文件和写入文件的名称char ch[Max]; //存放输入代码的缓冲区int nLine = 1; //初始化行数Table *table = new Table[Max];int choice;cout << "请输入读入方式:1:从文件中读,2:从键盘读(输入结束标志位#):\n";cin >> choice;switch(choice){int i;/****************************从文件读取***************************/ case 1:cout<<"Enter the input file name:\n";cin>>in_file_name;in.open(in_file_name);if(in.fail()) //打开display表读文件失败{cout<<"Inputput file opening failed.\n";exit(1);}cout<<"Enter the output file name:\n";cin>>out_file_name;out.open(out_file_name);outVar.open("变量表.txt");outCon.open("常量表.txt");if(out.fail()) //打开display表写文件失败{cout<<"Output file opening failed.\n";exit(1);}if(outVar.fail()) //打开变量表写文件失败{cout<<"VarOutput file opening failed.\n";exit(1);}if(outCon.fail()) //打开常量表写文件失败{cout<<"ConstOutput file opening failed.\n";exit(1);}in.getline(ch,Max,'#');Scanner(ch, strlen(ch),table,nLine); //调用扫描函数if(errorFlag == 1) //出错处理return 0;/*******************************把结果打印到各个表中***********************/ out <<"类型"<<" "<<"下标" <<endl;for( i = 0; i < TableNum;i ++)//打印displayout<< "(0x" <<hex << table[i].type<< " , "<< "0x" << hex << table[i].Index<< ")" <<endl; //在文件testout.txt中输出outCon << "下标" << " " << "常量值" << endl;for(i = 0;i < TableNum;i++) //打印常量表{if(table[i].type == 3){long num1;num1 = atoi(table[i].symbol);outCon<< "(0x" <<hex << table[i].Index << " , "<< "0x" << hex << num1 << ")" <<endl;}if(table[i].type == 4){double num2;num2 = atof(table[i].symbol);outCon<< "(0x" <<hex << table[i].Index << " , "<< "0x" << hex << num2<< ")" <<endl;}}outVar <<"类型"<<" "<< "变量名称" <<endl;for( i = 0; i < WordNum;i ++)//打印变量表outVar<< "(0x" <<hex << i<< " " << Word[i] << ")" <<endl; //在文件testout.txt中输出in.close();//关闭文件out.close();outVar.close();outCon.close();break;/***********************************从键盘输入****************************/ case 2:cin.getline(ch,Max,'#');Scanner(ch, strlen(ch),table,nLine); //调用扫描函数if(errorFlag == 1)return 0;cout << "\nDisplay表: \n";cout <<"类型"<<" "<<"下标" <<endl; //dos界面下for( i = 0; i < TableNum;i ++)cout<< "(0x" <<hex << table[i].type<< " , "<< "0x" << hex << table[i].Index<< ")" <<endl;cout << "\n常量表:\n" << "下标" << " " << "常量值" << endl;for(i = 0;i < TableNum;i++) //打印常量表{if(table[i].type == 3){long num1;num1 = atoi(table[i].symbol);cout<< "(0x" <<hex << table[i].Index << " , "<< "0x" << hex << num1 << ")" <<endl;}if(table[i].type == 4){char *num2;float num,num3;num = atof(table[i].symbol);num2 = gcvt(16,strlen(table[i].symbol),table[i].symbol);num3 = num - floor(num);cout << "(0x" << hex << table[i].Index << " , " << num2;Trans(num3,5) ;cout << ")" <<endl;}}cout <<"\n变量表:\n类型"<<" "<< "变量名称" <<endl;for( i = 0; i < WordNum;i ++)//打印变量表cout<< "(0x" <<hex << i<< " " << Word[i] << ")" <<endl; //在文件testout.txt中输出break;}return 0;}附录2:在状态转换图中各个状态表示的种类、种别编码、解释如下表:附录3:(状态转换图)空格换行tab。