课程实验报告
课程名称 | 编译原理 | 班级 | xxx | 实验日期 | xxx |
姓名 | xxx | 学号 | xxx | 实验成绩 | |
实验名称 | 实验1:词法分析程序 | ||||
实 验 目 的 及 要 求 | 实验要求: 自己设计任一语言,描述其词法,设计一个此语言的词法分析器,任选语言实现,并且能够顺利执行。 实验目的:
| ||||
实 验 环 境 | 操作系统:Win 7或以上版本 语言版本:C语言 开发工具:vs2019 | ||||
实 验 内 容 | 在设计词法分析器之前需要先定义语言,主要有如下几个方面。
| ||||
算 法 描 述 及 实 验 步 骤 | 算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字种类,拼出相应的单词符号。
首先设置三个变量:(1)token用来存放构成单词符号的字符串;(2)sum用来存放整形单词;(3)syn用来存放单词符号的种别码。扫描子程序主要部分流程图: | ||||
调 试 过 程 及 实 验 结 果 | | ||||
总 结 | 此次实验还是很有意思的,最终跑通的时候也是非常有成就感,个人感觉不用拘泥于用什么算法,只需要捋清楚自己的思路,如何设计才能使这个程序能正确识别?主要有一个优先级的思路,空格和换行符会被跳过,然后先判断是否为数字或者字母,在进行相应处理,然后进行一些特殊界符的判断,如字符串、注释等。我认为代码就足以很好的说清楚这个流程。这个程序暂时只使用常用符号(.)来支持小数,如果需要更多,可以在judge中的isdigit()后进行修改,改起来并不困难。显然,judge函数中的函数还可以拆成更细致的几个函数,但这就等以后再补全了。 | ||||
附 录 | #define_CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #define_KEY_WORDEND"waiting for your expanding" usingnamespace std; typedefstruct//词的结构,二元组形式(单词种别,单词自身的值) { int typenum; //单词种别 char* word; }WORD; char input[255]; char token[255] = ""; int p_input; //指针 int p_token; char ch; char* rwtab[] = {"张文俊", "begin","if","then","while","do","end","int","main","else","float","double","return","cout","printf",_KEY_WORDEND }; WORD* scanner();//扫描 int main() { int over = 1; WORD* oneword = newWORD; //实现从文件读取代码段 cout <<"read something from data.txt"<< endl; FILE* fp; if ((fp = freopen("data.txt", "r", stdin)) == NULL) { printf("Not found file!\n"); return 0; } else { while ((scanf("%[^#]s", &input)) != EOF) { p_input = 0; printf("your words:\n%s\n", input); while (over < 1000 && over != -1) { oneword = scanner(); if (oneword->typenum < 1000) { if (oneword->typenum != 999) cout <<"( "<< oneword->typenum <<","<< oneword->word <<" )"<< endl; } over = oneword->typenum; } scanf("%[^#]s", input); } } return 0; } //从输入缓冲区读取一个字符到ch中 char m_getch() { ch = input[p_input]; p_input++; return ch; } //去掉空白符号 void getbc() { while (ch == ' ' || ch == 10) { ch = input[p_input]; p_input++; } } //拼接单词 void concat() { token[p_token] = ch; p_token++; token[p_token] = '\0'; } //判断是否字母 int letter() { if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') return 1; else return 0; } //判断是否数字 int digit() { if (ch >= '0' && ch <= '9') return 1; else return 0; } //检索关键字表格 int reserve() { int i = 0; while (strcmp(rwtab[i], _KEY_WORDEND)) { if (!strcmp(rwtab[i], token)) return i + 1; i++; } return 10;//如果不是关键字,则返回种别码10 } //回退一个字符 void retract() { p_input--; } //词法扫描程序 WORD* scanner() { WORD* myword = newWORD; myword->typenum = 10; //初始值 myword->word = ""; p_token = 0; //单词缓冲区指针 m_getch(); getbc();//去掉空白 if (letter())//判断读取到的首字母是字母 { //如int while (letter() || digit()) { concat(); //连接 m_getch(); } retract(); //回退一个字符 myword->typenum = reserve();//判断是否为关键字,返回种别码 myword->word = token; return myword; } elseif (digit()) //判断读取到的单词首字符是数字 { while (digit()) //所有数字连接起来 { concat(); m_getch(); } retract(); //数字单词种别码统一为20,单词自身的值为数字本身 myword->typenum = 20; myword->word = token; return(myword); } elseswitch (ch) { case'=': m_getch();//首字符为=,再读取下一个字符判断 if (ch == '=') { myword->typenum = 39; myword->word = "=="; return(myword); } retract();//读取到的下个字符不是=,则要回退,直接输出= myword->typenum = 21; myword->word = "="; return(myword); break; case'+': myword->typenum = 22; myword->word = "+"; return(myword); break; case'-': myword->typenum = 23; myword->word = "-"; return(myword); break; case'/'://读取到该符号之后,要判断下一个字符是什么符号,判断是否为注释 m_getch();//首字符为/,再读取下一个字符判断 if (ch == '*') // 说明读取到的是注释 { m_getch(); while (ch != '*') { m_getch();//注释没结束之前一直读取注释,但不输出 if (ch == '*') { m_getch(); if (ch == '/')//注释结束 { myword->typenum = 999; myword->word = "注释"; return (myword); break; } } } } else { retract();//读取到的下个字符不是*,即不是注释,则要回退,直接输出/ myword->typenum = 25; myword->word = "/"; return (myword); break; } case'*': myword->typenum = 24; myword->word = "*"; return(myword); break; case'(': myword->typenum = 26; myword->word = "("; return(myword); break; case')': myword->typenum = 27; myword->word = ")"; return(myword); break; case'[': myword->typenum = 28; myword->word = "["; return(myword); break; case']': myword->typenum = 29; myword->word = "]"; return(myword); break; case'{': myword->typenum = 30; myword->word = "{"; return(myword); break; case'}': myword->typenum = 31; myword->word = "}"; return(myword); break; case',': myword->typenum = 32; myword->word = ","; return(myword); break; case':': m_getch(); if (ch == '=') { myword->typenum = 18; myword->word = ":="; return(myword); break; } else { retract(); myword->typenum = 33; myword->word = ":"; return(myword); break; } case';': myword->typenum = 34; myword->word = ";"; return(myword); break; case'>': m_getch(); if (ch == '=') { myword->typenum = 37; myword->word = ">="; return(myword); break; } retract(); myword->typenum = 35; myword->word = ">"; return(myword); break; case'<': m_getch(); if (ch == '=') { myword->typenum = 38; myword->word = "<="; return(myword); break; } elseif (ch == '<') { myword->typenum = 42; myword->word = "<<"; return(myword); break; } else { retract(); myword->typenum = 36; myword->word = "<"; return (myword); } case'!': m_getch(); if (ch == '=') { myword->typenum = 40; myword->word = "!="; return(myword); break; } retract(); myword->typenum = -1; myword->word = "ERROR"; return(myword); break; case' " ': myword->typenum = 41; myword->word = " \" "; return(myword); break; case'\0': myword->typenum = 1000; myword->word = "OVER"; return(myword); break; case'#': myword->typenum = 0; myword->word = "#"; return (myword); break; default: myword->typenum = -1; myword->word = "ERROR"; return(myword); break; } } |