词法分析器(含完整源码)

合集下载

编译原理课程设计—词法分析器

编译原理课程设计—词法分析器

编译原理课程设计(一)——词法分析器1、题目编写程序实现一个简易的词法分析器。

2、实验目的对一段程序代码进行词法分析,将程序段中的关键字、标识符、常数、运算符、界符按照一定的种别编码分析出来。

3、环境及工具操作系统:windows XP ;使用工具:Microsoft Visual C++ 6.0; 编程语言:C 语言;4、分析程序输入:从文件中读入程序段;程序输出:由单词种别和单词符号的属性值组成的二元式;单词种别通常使用整数编码,编码方式可以有多种,在设计词法分析器之前应确定一种程序处理起来较方便的编码方式。

当一个种别中含有多个单词符号时,在分析出其属于哪个种别的时候应同时给出其单词符号属性,本程序为方便起见,采用单词符号本身来作为其属性,以标识同种别种的不同单词符号。

标识符及关键字的识别:字母开头的字母和数字组成的串是多数编程语言的标识符,所以我们的简易词法分析器中,将标识符定义为这种字母数字串。

当第一个字母为字母且紧接着的字符为数字或字母时,应将其串接在一起为一个单词,直到紧跟着的不在是字母数字时。

由于关键字通常为一个单词,则这样得到的串可能是标识符也可能是关键字,又因为一种语言的关键字通常是有限个,则我们可以构造一个存放所有关键字的表,查询关键字表,可以判断得到的串是否为关键字。

界符和运算符的识别:它们多为当个字符,建立两个分别存放界符合运算符的表,读取字符后,进行查表便可以得出它们的类型。

为方便词法分析器的设计,可以使用状态转换图,根据一种特定的编程语言先设计出其状态转换图才能更好将其用代码实现。

典型状态转换图结构如下:(a)有不含回路含分支的状态节点:对应if …else if …else …语句;(b)有含回路的状态节点:对应while …if …语句。

(b )5、状态转换图6、程序框架描述程序中编写了以下函数,各个函数实现的作用如下:1. GetChar():将下一输入的字符读入到全局变量ch中,搜素指示器前移一个字符的位置。

编译原理词法分析器-ll1-lr0-python实现代码

编译原理词法分析器-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语言版

编译原理----词法分析程序----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);}}。

【编译原理】词法分析(CC++源代码+实验报告)

【编译原理】词法分析(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语言词法分析器下面是一个基于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]+`表示忽略空格和换行符;`.`表示匹配到了其他未定义的字符,就打印出异常信息。

词法分析器源代码

词法分析器源代码

词法分析器源代码#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语言的一些基本知识,特别是对文件,字符串进行基本操作的方法。

编译原理词法分析和语法分析报告+代码(C语言版)[1]

编译原理词法分析和语法分析报告+代码(C语言版)[1]

词法分析一、实验目的设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。

二、实验要求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)……三、词法分析程序的算法思想:算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。

3.1 主程序示意图:主程序示意图如图3-1所示。

其中初始包括以下两个方面:⑴关键字表的初值。

关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。

如能查到匹配的单词,则该单词为关键字,否则为一般标识符。

关键字表为一个字符串数组,其描述如下:Char *rwtab[6] = {“begin”, “if”, “then”, “while”, “do”, “end”,};图3-1(2)程序中需要用到的主要变量为syn,token和sum3.2 扫描子程序的算法思想:首先设置3个变量:①token用来存放构成单词符号的字符串;②sum用来整型单词;③syn用来存放单词符号的种别码。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
}//error
void Scanner(char ch[],int chLen,Table table[Max],int nLine) {
int chIndex = 0;
while(chIndex < chLen) //对输入的字符扫描 { /**************************处理空格和 tab ************************/
六、总结:
词法分析是构造编译器的起始阶段,也是相应比较简单的一个环节。词法分析的主要任 务是:根据构造的状态转换图,从左到右逐个字符地対源程序进行扫描,识别开源程序中具 有独立含义的最小语法单位——符号或单词,如变量标识符,关键字,常量,运算符,界符 等。
然后将提取出的标识符以内码的形式表示,即用 int 类型的数字来表示其类型和在 display 表中的位置,而无须保留原来标识符本身的字符串,这不仅节省了内存空间,也有 利于下一阶段的分析工作。
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; //错误标志
当然,在扫描源程序串的同时,进行一些简单的处理,如删除空格、tab、换行等无效 字符,也进行了一些基本的错误处理,如变量长度的判别,有些不合词法规则的标识符判别 等。总之,严格说来,词法分析程序只进行和词法分析相关的工作。
七、实验感想:
通过此次实验,让我了解到如何设计、编制并调试词法分析程序,加深对词法分析原理 的理解;熟悉了构造词法分析程序的手工方式的相关原理,使用某种高级语言(例如 C++语 言)直接编写此法分析程序。另外,也让我重新熟悉了 C++语言的相关内容,加深了对 C++ 语言的用途的理解。
部分结果如下:
其他测试及结果如下:
③、出错处理; 注:若有错误,则只指出错误,不输出各个表;
(5)、评价: 这个小语言程序基本上能完成词法分析阶段的工作,识别诸如 begin,if 等保留字;识
别非保留字的一般标识符(有下划线、字符、数字,且第一个字符不能是数字)。识别数字 序列(整数和小数);识别:=,<=,>=之类的特殊符号以及;,(,)等界符。在扫描源程序 串的同时,能进行一些简单的处理,如删除空格、tab、换行等无效字符,也进行了一些基 本的错误处理,如变量长度的判别等。
附录 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 //界符最大个数
经过分析,我们在现有局限性的基础上,设计出一种折中的表结构,即在表结构中只添 加标识符在其相应表中的对应下表,标记符类型码等关键的几处,这样既能 唯一确定一标 识符,达到该实验的要求,同时又为表保留了很好的扩充性,以达到后续实验的要求。表结 构设计好后,其余的工作就是提取字符串和写入 display 表,在提取单字符还是双字符组成 的运算符时有些麻烦,不过利用数据结构的相关知识也是容易做到。
// 界符
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; }
/***************************标识符***************************************/ 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 ++;
总之这个小语言词法分析器能提供以上所说明到的语法描述的功能……源自三、实验步骤:1、测试评价
(1)、测试 1:能说明一些简单的变量,如关键字、一般标识符、界符等; (2)、测试 2:能输出结果:单词符号(内码形式)、各种信息表(如符号表、常量表等); (3)、测试程序:
var x,y,z; begin
x:=2; y:=3; if (x+5>=y*y) then
"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[] = {'(', ')' , ',' , ';' , '.' , '[' , ']' , ':' , '{' , '}' , '"'};
begin z:=y*y-x; z:=z+x*x;
end else
z:=x+y;
prn z; end. (4)、结果: ①、从键盘读入;
部分结果如下:
(类型:该标识符所属的类型,如关键字,变量等;下标:该标识符所对应表(如变量标 识符表,常量标识符表等)中其相应的位置,下同)
②、从文件读入,输出到文件;
} } }
table[TableNum].Index = WordNum; strcpy(Word[WordNum++],str); table[TableNum].type = 2; //变量标识符 strcpy(table[TableNum].symbol,str); table[TableNum].line = nLine; TableNum ++;
strcpy(table[TableNum].symbol,str); table[TableNum].type = 1; //关键字 table[TableNum].line = nLine; table[TableNum].Index = i; TableNum ++; break; } if(i >= MaxKeyWord) //不是关键字 {
while(ch[chIndex] == ' ' || ch[chIndex] == 9 ) //忽略空格和 tab { chIndex ++; } /***************************处理换行符*************************************/ while(ch[chIndex] == 10) //遇到换行符,行数加 1 { nLine++;chIndex ++;}
相关文档
最新文档