编译原理:c语言词法分析器的实现

  • 一、前言
  • 二、什么是词法分析器
    • 定义
    • 输出
  • 三、实现过程
    • 如何实现
    • 部分代码
  • 四、测试
    • 测试用例
    • 输出结果

一、前言

词法分析和语法分析是编译原理中必要的部分,是需要花费一定时间去学习理解的,本文简单介绍了使用c语言如何编写c语言的词法分析器。(ps:完整代码的链接在文末)

二、什么是词法分析器

定义

词法分析器的功能输入源程序,按照构词规则分解成一系列单词符号。单词是语言中具有独立意义的最小单位,包括关键字、标识符、运算符、界符和常量等。
(1) 关键字:是由程序语言定义的具有固定意义的标识符。例如begin,end,if,while都是保留字。这些字通常不用作一般标识符。
(2) 标识符:用来表示各种名字,如变量名,数组名,过程名等等。
(3) 常数 :常数的类型一般有整型、实型、布尔型、文字型等。
(4) 运算符:如+、-、*、/等等。
(5) 界符 :如逗号、分号、括号、等等。

输出

有了对词法分析器的定义,我们编写的词法分析器的输出理所当然应当是如下的形式:
(单词,单词属性,id(种别码))
如:(if,关键字,3)
id通常情况下可以自己定义,例如无符号整数的id可以设为1,只要能区别不同的属性即可。(ps:如果在编写时有对应的种别码表,照着写就完事儿了。)

种别码表示例
单词符号 种别码
NUM 0
Letter 1
main 2

三、实现过程

如何实现

  1. 读到空格则略过,读下一个字符;若读到的是字母,就再接着读,直到读到的既不是字母也不是数字也不是下划线,并将读到的写入到token数组
  2. 若读到的是数字,直到读到的不是数字或小数点,将读到的写入到token数组;
  3. 若读到的是<|>|=,则再读入下一位,若为=,则该运算符为<=|>=|==,若为其他字符,则返回<|>|=的种别码;
  4. 若读到的是/,则读下一位,若为*,则说明之后为多行注释,一直读入直到读入*,并判断下一位是否为/,若是则注释结束,不是继续往下一位读入;若读入\n,则行数加一,若读入的字符与以上都不匹配,则报错,并输出出错行数;
  5. 若读到/时,下一位又读到/,即读到的是单行注释,此时判断下一位是否为\n,若是,则注释结束,不是则继续读入下一位。

部分代码

--建立分析时的缓冲空间
char ch =' '; //存放读入当前的输入字符
int Line_NO;    //纪录行号
--建立关键字表
struct keywords{ //关键字char lexptr[MAXBUF];int token;
};struct keywords symtable[MAX];
char str[MAX][10]={"int","char","float","main","double","case","for","if","auto","else","do","while","void","static","return","break","struct","const","union","switch","typedef","enum"}; //记为3~24
--初始化关键字表
void init(){ //关键字表初始化int j;for(j=0; j<MAX; j++){strcpy(symtable[j].lexptr,str[j]);symtable[j].token=j+3;}
}
--Iskeyword函数分析关键字
int Iskeyword(char * is_res){    //对关键字进行搜索int i;for(i=0;i<MAX;i++){if((strcmp(symtable[i].lexptr,is_res))==0) break;}if(i<MAX)return symtable[i].token;      elsereturn 0;
}
--IsLetter函数分析字母
int IsLetter(char c){    //判断是否为字母if(((c>='a')&&(c<='z'))||((c>='A')&&(c<='Z')))return 1;elsereturn 0;
}
--IsDigit函数分析数字
int IsDigit(char c){ //判断是否为数字if(c>='0'&&c<='9')return 1;elsereturn 0;
}
--碰到空格、tab跳过
if(ch==' '||ch=='\t'){}
else if(ch=='\n')Line_NO++;
--忽略大小写
if((ch<='A')&&(ch>='Z'))     ch=ch+32;
--字符的处理,包括注释的去除,非法字符
switch(ch){  //符号case'(' :fprintf(fpout,"%s\t\t%d\t\t分界符\n","(",26);break;case')' :fprintf(fpout,"%s\t\t%d\t\t分界符\n",")",27);break;case'[' :fprintf(fpout,"%s\t\t%d\t\t分界符\n","[",28);break;case']' :fprintf(fpout,"%s\t\t%d\t\t分界符\n","]",29);break;case';' :fprintf(fpout,"%s\t\t%d\t\t分界符\n",";",30);break;case'.' :fprintf(fpout,"%s\t\t%d\t\t分界符\n",".",31);break;case',' :fprintf(fpout,"%s\t\t%d\t\t分界符\n",",",32);break;case':' :fprintf(fpout,"%s\t\t%d\t\t分界符\n",":",33);break;case'{' :fprintf(fpout,"%s\t\t%d\t\t分界符\n","{",34);break;case'}' :fprintf(fpout,"%s\t\t%d\t\t分界符\n","}",35);break;case'"' :fprintf(fpout,"%s\t\t%d\t\t分界符\n","\"",36);break;case'+' :fprintf(fpout,"%s\t\t%d\t\t运算符\n","+",37);break;case'-' :fprintf(fpout,"%s\t\t%d\t\t运算符\n","-",38);break;case'*' :fprintf(fpout,"%s\t\t%d\t\t运算符\n","*",39);break;case'=' :fprintf(fpout,"%s\t\t%d\t\t运算符\n","=",40);break;case'>' :{ch=fgetc(fpin);if(ch=='=') fprintf(fpout,"%s\t\t%d\t\t运算符\n",">=",41);else{fprintf(fpout,"%s\t\t%d\t\t运算符\n",">",42);fseek(fpin,-1L,SEEK_CUR);}}break;case'<' :{ch=fgetc(fpin);if(ch=='=')fprintf(fpout,"%s\t\t%d\t\t运算符\n","<=",43);else{fprintf(fpout,"%s\t\t%d\t\t运算符\n","<",44);fseek(fpin,-1L,SEEK_CUR);}}break;case'%' :{ch=fgetc(fpin);if(ch=='d'||ch=='f'||ch=='s'||ch=='x')fprintf(fpout,"%s\t\t%d\t\t输出格式符\n","\%",45);elsefprintf(fpout,"%s\t\t%d\t\t运算符\n","\%",46);}break;case'/' :{ch=fgetc(fpin);//出现在/  /之间的全部作为注释部分处理if(ch=='*'){while(ch!='/'&&ch!=EOF)ch=fgetc(fpin);if(ch==EOF) fprintf(fpout,"缺少一个'/'");}else if(ch=='/'){while(ch!='\n'&&ch!=EOF)ch=fgetc(fpin);}else{fprintf(fpout,"%s\t\t%d\t\t运算符\n","/",47);fseek(fpin,-1L,SEEK_CUR);}}break;default :fprintf(fpout,"在第%d行无法识别的字符\t%c\n",Line_NO,ch);   //非法字符
}

四、测试

测试用例

测试文件s.txt

int main(void)
{int a1,b;a1=103;b=2;if(a1>=b){/*多行
注释*/a1=a1*b;//单行注释}printf("%d",a1);return 0;
}

输出结果

输出文件r.txt

int      3       关键字
main    6       关键字
(       26      分界符
void    15      关键字
)       27      分界符
{       34      分界符
int     3       关键字
a1      1       标识符
,       32      分界符
b       1       标识符
;       30      分界符
a1      1       标识符
=      40      运算符
103     2       无符号整数
;       30      分界符
b       1       标识符
=      40      运算符
2       2       无符号整数
;       30      分界符
if      10      关键字
(       26      分界符
a1      1       标识符
>=      41      运算符
b       1       标识符
)       27      分界符
{       34      分界符
a1      1       标识符
=      40      运算符
a1      1       标识符
*       39      运算符
b       1       标识符
;       30      分界符
}       35      分界符
printf  1       标识符
(       26      分界符
"      36      分界符
%       45      输出格式符
"      36      分界符
,       32      分界符
a1      1       标识符
)       27      分界符
;       30      分界符
return  17      关键字
0       2       无符号整数
;       30      分界符
}       35      分界符

完整代码: https://download.csdn.net/download/yiwanxianyutang/20089286?spm=1001.2014.3001.5501

编译原理:c语言词法分析器的实现相关推荐

  1. html解析器编译原理,编译原理实验报告词法分析器(内含源代码).docx

    编译原理实验报告词法分析器(内含源代码) 编译原理实验(一) --词法分析器 实验描述 运行环境:vc++2008 对某特定语言A ,构造其词法规则. 该语言的单词符号包括: 1该程序能识别的单词符号 ...

  2. 【编译原理】语言认知之Java、Python、C++快速排序三者运行效率与开发效率比较

    [编译原理]语言认知之Java.Python.C++快速排序&三者运行效率与开发效率比较 一.实验目的 二.实验环境 三.实验步骤 四.快速排序程序 五.实验结果 六.总结 一.实验目的 强化 ...

  3. 编译原理SNL语言编译器实验报告

    完成实验内容 实验要求: (1)设计并实现SNL程序设计语言的编译程序 (2)四个必做: 词法分析模块 语法分析模块(递归下降方法) 语法分析模块(LL(1)方法) 语义分析模块 (3)编程语言不限 ...

  4. 大前端开发者需要了解的基础编译原理和语言知识

    转自:https://yq.aliyun.com/articles/180879 在我刚刚进入大学,从零开始学习 C 语言的时候,我就不断的从学长的口中听到一个又一个语言,比如 C++.Java.Py ...

  5. micropython编译原理_C语言嵌入式Linux高级编程第9期:CPU和操作系统入门视频课程...

    嵌入式开发是一门交叉学科. 它要求我们的嵌入式工程师,不仅学习C语言.汇编.软件工程等软件层面的知识技能,还要求对CPU内部工作机制.计算机系统架构.操作系统原理.编译器等都有一个全局的认识和把握. ...

  6. 太原理工 编译原理 c语言,太原理工大学编译原理实验

    <太原理工大学编译原理实验>由会员分享,可在线阅读,更多相关<太原理工大学编译原理实验(19页珍藏版)>请在人人文库网上搜索. 1.本科实验报告课程名称: 编译原理 实验项目: ...

  7. C++:编译原理实验之词法分析器

    一.实验目的 学会针对DFA转换图实现相应的高级语言源程序. 深刻领会状态转换图的含义,逐步理解有限自动机. 掌握手工生成词法分析器的方法,了解词法分析器的内部工作原理. 加强对C语言的掌握 二.实验 ...

  8. 编译原理:简单词法分析器的设计与实现

    一.实验目的: 设计.编制并调试一个简单的c语言词法分析程序,加深对词法分析原理的理解 二.实验要求: 对单词的构词规则有明确的定义: 编写的分析程序能够正确识别源程序中的单词符号: 识别出的单词以( ...

  9. 【编译原理】语言的定义

    文章目录 推导和规约 句子和句型 短语,直接短语和句柄 素短语 推导和规约 下面是关于推导的定义: 当n=1时,即符号串a0经过1步推导出an,记为直接推导. 如下,推导的过程就是用产生式的右部替换左 ...

  10. 编译原理 SysY语言的词法分析程序

    实验目的与内容 对SysY语言进行词法分析,可以查出语言中可能包含的词法错误. 从控制台输入字符串,如有出错则输出错误,没有错误则按照二元组的方式输出 设计方法 对SysY语法进行分析如下: (1) ...

最新文章

  1. 计算机程序水仙花数,水仙花数
  2. 图像和视频的快速去雾算法研究
  3. poj 1556 (Dijkstra + Geometry 线段相交)
  4. zoj3195 联通树上三个点的路径长
  5. 行人跟踪python_使用Python为初学者构建AI汽车和行人跟踪
  6. (*长期更新)软考网络工程师学习笔记——Section 4 物理层的其它知识
  7. 【加解密学习笔记:第一天】操作系统基础知识
  8. JS手动实现一个new操作符
  9. labview csv文件处理_LabVIEW 相关知识点分类汇总
  10. vue你不知道的奇淫绝技
  11. c c++ 实现代理服务器
  12. 当更高性能来到平板 — ThinkPad X1 Tablet Evo 长测
  13. 科略教育—太极拳理与企业家管理理念
  14. android播放系统音效,Android用SoundPool播放音效
  15. 中式红木装修——优雅传统之美
  16. python爬虫爬取实习僧岗位信息并存入excel数据表中
  17. doNet面试宝典-常见整理(重复率高)
  18. SS中添加多用户失败
  19. 联想计算机boss设置,联想电脑bios设置图解教程
  20. 用Mysql做个人信息管理系统_个人信息管理系统数据库设计精选.doc

热门文章

  1. java .entryset_Java中map的entrySet()方法返回的是什么内容啊?有点晕
  2. 西门子滚筒洗衣机教程_西门子洗衣机优缺点
  3. Java正则表达式实现计算器_Python利用正则表达式实现计算器算法思路解析
  4. android 更换系统壁纸,Android使用线程更换壁纸
  5. laravel 配置邮件发件人_Jenkins中配置自动化测试项目
  6. acm运行时错误_计人即讯|ACM纳新赛
  7. 洛谷 P1017 进制转换
  8. c# 盖尔-沙普利算法的改进
  9. java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException
  10. web工程was部署