词法分析器设计与实现
开篇
编译,简单的说,就是把源程序转换为可执行程序。从hello world 说程序运行机制 里面简单的说明了程序运行的过程,以及一个程序是如何一步步变成可执行文件的。在这个过程中,编译器做了很多重要的工作。对底层该兴趣的我,自然的,也就迫切想搞清楚编译的内部实现,也就是编译的原理。
这篇文章主要说的是编译器前端,词法分析器的原理,最后会给出一个词法分析器的简单实现。
介绍
编译简单的说,就是把源程序转化为另一种形式的程序,而其中关键的部分就是理解源程序所要表达的意思,才能转化为另一种源程序。
可以用一个比喻来说明问题:人A和人B想要交谈,但是他们都不知道彼此的语言,这就需要一个翻译C,同时懂得A和B的语言。有了C做中间层,A和B才能正常交流。C的作用就有点像编译器,它必须能理解源程序所要表达的意思,才能把信息传递给另一个。
编译器也一样,它的输入是语言的源文件(一般可以是文本文件)对于输入的文件,首先要分离出这个输入文件的每个元素(关键字、变量、符号、、)
然后根据语言的文法,分析这些元素的组合是否合法,以及这些组合所表达的意思。
程序设计语言和自然语言不一样,都是用符号来描述,每个特定的符号表示特定的意思,而且程序设计语言是上下文无关的。上下文无关就是某一个特定语句所要表达的意思和它所处的上下文没有关系,只有它自身决定。
这篇博文主要说的就是词法分析,也就是把输入的符号串整理成特定的词素。
词法分析
示例:
比如如下的代码段:
while(i>=j) i--
词法分析器设计
分析器的简单实现
上文主要介绍了词法分析的一些相关的知识,而对词法分析器的具体实现还没有具体提到,为了能更好的理解词法分析,我写了一个简单的词法分析器。
虽然说是语法分析器,但实现的功能很简单,只是对输入的程序把注释去掉,其中用到了上面关于状态转换图部分的知识。
分析:
一般的程序设计语言, 注释部分的形式为;
/* 注释部分、、、、*/
我们的程序总是顺序的一个一个字符读取输入文件的。我们的目的是把注释部分去掉,那么对于输入的字符流,我们只要识别出“/*”就知道后面的部分是注释部分,直到识别输入流中出现"*/"为止。
对字符流的处理是一个一个进行的,每读入一个字符,就判断,如果字符是“/”,就说明后面 的部分可能是注释,再看下一个输入字符,如果是“*”, 就是上面所说的情况:“ /*”那么后面的部分就是注释部分,然后再用相同的方法找出"*/"就可以了。
这个识别的过程就可以用状态转换图来清晰的表示:
对于读入的每个符号都要进行判断,如果是“/”说明后面的部分有可能是注释,进入状态1。如果后面的输入是“*”那么就可以确定以后的内容为注释内容,如果后面的输入不是"*",说明后面的内容不是注释,前面出现的"/"可能是做除号使用,如“5/3”
其实上面的流程图也就对应了程序实现的逻辑,可以用switch-case 来实现,对于每个输入,判断后跳转到相应的状态,然后继续判断。
下面是程序伪代码:
while((ch=getchar())!=EOF)
switch(state)
case 1 :if ch=="/",state=2,break;
case 2: if ch=="*",state=3
else state=1;break;
case 3:..........
case 4:..........
词法分析器
这个程序比较简单,就不给出源代码了。接下来是一个简单的词法分析器的代码,可以实现对关键字(如 while end if 等),对数字的识别,去掉空格符等。
下面是这个分析器的功能:
1、 待分析的简单语言的词法
(1) 关键字:
begin if then while do end
所有关键字都是小写。
(2) 运算符和界符:
:= + – * / < <= <> > >= = ; ( ) #
(3) 其他单词是标识符(ID)和整型常数(NUM),通过以下正规式定义:
ID=letter(letter| digit)*
NUM=digit digit *
(4) 空格由空白、制表符和换行符组成。空格一般用来分隔ID、NUM,运算符、界符和关键字,词法分析阶段通常被忽略。
2、 各种单词符号对应的种别码
词法分析程序的功能
输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。
其中:syn为单词种别码;
token为存放的单词自身字符串;
sum为整型常数。
下面是程序源代码,基于上面的讨论,应该比较好了解了。
#include<stdio.h>
#include<string.h>
#include<iostream.h>
char prog[80],token[8];
char ch;
int syn,p,m=0,n,row,sum=0;
char *rwtab[6]={"begin","if","then","while","do","end"};
void scaner()
{
/*
共分为三大块,分别是标示符、数字、符号,对应下面的 if else if 和 else
*/
for(n=0;n<8;n++) token[n]=NULL;
ch=prog[p++];
while(ch==' ')
{
ch=prog[p];
p++;
}
if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')) //可能是标示符或者变量名
{
m=0;
while((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
{
token[m++]=ch;
ch=prog[p++];
}
token[m++]='\0';
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')) //数字
{
{
sum=0;
while((ch>='0'&&ch<='9'))
{
sum=sum*10+ch-'0';
ch=prog[p++];
}
}
p--;
syn=11;
if(sum>32767)
syn=-1;
}
else switch(ch) //其他字符
{
case'<':m=0;token[m++]=ch;
ch=prog[p++];
if(ch=='>')
{
syn=21;
token[m++]=ch;
}
else if(ch=='=')
{
syn=22;
token[m++]=ch;
}
else
{
syn=23;
p--;
}
break;
case'>':m=0;token[m++]=ch;
ch=prog[p++];
if(ch=='=')
{
syn=24;
token[m++]=ch;
}
else
{
syn=20;
p--;
}
break;
case':':m=0;token[m++]=ch;
ch=prog[p++];
if(ch=='=')
{
syn=18;
token[m++]=ch;
}
else
{
syn=17;
p--;
}
break;
case'*':syn=13;token[0]=ch;break;
case'/':syn=14;token[0]=ch;break;
case'+':syn=15;token[0]=ch;break;
case'-':syn=16;token[0]=ch;break;
case'=':syn=25;token[0]=ch;break;
case';':syn=26;token[0]=ch;break;
case'(':syn=27;token[0]=ch;break;
case')':syn=28;token[0]=ch;break;
case'#':syn=0;token[0]=ch;break;
case'\n':syn=-2;break;
default: syn=-1;break;
}
}
int main()
{
p=0;
row=1;
cout<<"Please input string:"<<endl;
do
{
cin.get(ch);
prog[p++]=ch;
}
while(ch!='#');
p=0;
do
{
scaner();
switch(syn)
{
case 11: cout<<"("<<syn<<","<<sum<<")"<<endl; break;
case -1: cout<<"Error in row "<<row<<"!"<<endl; break;
case -2: row=row++;break;
default: cout<<"("<<syn<<","<<token<<")"<<endl;break;
}
}
while (syn!=0);
}
改程序在C-free5上调试通过
下面是程序截图:
小结
这里主要说的是编译器中的词法分析,还介绍了词法分析的一些相关知识,最后给出了一个很简单的词法分析器的实现。
参看资料:编译原理
如有转载请注明出处:http://www.cnblogs.com/yanlingyin/
词法分析器设计与实现相关推荐
- c语言词法分析程序设计,C语言词法分析器设计与实现.doc
>? C语言词法分析器设计与实现 ? C语言词法分析器的设计与实现 一.实验目的 1.强化对系统软件综合工程实现能力.规划能力的训练: 2.加强对词法分析原理.方法和基本实现技术的理解: 二.实 ...
- 词法分析器(实现报告)
实验报告 名称: 编译原理:词法分析器 设计: 03 计算机B班 kikikind 086 指导老师: 周艳明 时间: 2006-4-13 一. 编程实现 1.本程序在VC ...
- 【编译原理】学习笔记以及课程设计
编译原理 教材用的是<编译原理>(第三版)陈火旺著,电子版戳这里密码:x4ut 课后习题答案戳这里密码:nkv9 教学PPT戳这里密码:0tfz PPT习题答案戳这里密码:v9ct (侵删 ...
- 我看过的编译原理方面的好文章
本文不定期更新,最后更新于2019-7-6 编译原理 编译原理三大经典书籍(龙书 虎书 鲸书) 前端为什么要会正则表达式 - 知乎 一次性搞懂JavaScript正则表达式之引擎 - 掘金 没有AST ...
- 分享成为高效程序员的7个重要习惯
作者:Phil Chu 作为软件工程师,你希望从工作中获得的是:稳定的薪水.参与好项目的机会.好工作的跳板或只是和其他程序师成为好基友.这里的"高效",我指的是按时完符合要求的项目 ...
- 《编译原理》实验教学大纲
<编译原理>实验教学大纲 课程编号: 773033 课程名称:编译原理 英文名称:Compiler Principle 课程类型: 模块课 学 时:5 学 分:4 适用对象: 软件开发各专 ...
- 《编译原理》课程教学大纲
<编译原理>课程教学大纲 课程编号:773033 课程名称(中/英文):编译原理 / Compiler Principle 课程类型: 模块课 总 学 时:5学时/周 讲课学时:4学时/周 ...
- python输入一个四位数、逆序输出这四位数_输入一个四位数,输出这个四位数的逆序数,比如输入1234,输出4321_学小易找答案...
[单选题]斗拱上的方形木块叫做 [简答题]巧克力包装设计 [计算题]对于LL(1)文法 G(E) S → (L) | aS' S' → S |ε L → SL' L' → ,SL'|ε (1 ) 构造 ...
- 编译原理课程实践——实现一个初等函数运算语言的解释器或编译器
编译原理课程实践--实现具有初等函数运算语言的解释器或编译器 作者:Sylvan Ding |转载请注明文章出处! 摘要:本文主要内容是设计词法分析器.语法分析器(LL(1).SLR(1))和语义分析 ...
最新文章
- tcp_handle_req: Made 4 read attempts but message is not complete yet - closing connection
- C#中利用Socket实现网络语音通信[初级版本]
- 7-44 基于词频的文件相似度 (30 分)(思路加详解+set容器简便做法)兄弟们冲呀呀呀呀呀 今天你AC了吗
- 企业是否应该实现对客户需求的快速响应_互联网企业的数据化迭代和数据化应用...
- 安卓图标_干货 | 安卓界面系统规范
- docker run命令_CVE-2019-14271:Docker cp命令漏洞分析
- 跨域问题时的Filter无效
- ssis工具_SSIS中的DTExec实用工具概述
- c#中params关键字应用
- PKCS #1 RSA Encryption Version 1.5
- bzoj 1856: [Scoi2010]字符串(卡特兰数)
- 如何用纯 CSS 创作一只卡通鹦鹉
- LoadRunner测试ajax框架,回放后系统中没有产生数据解决方法
- 数据分析第一步 | 做好数据埋点
- matlab画出n的阶乘,matlab计算n的阶乘函数程序
- 2017年的知识清单
- SMSBMS超市订单管理系统详解(一:准备工作)
- 编码通信与魔术初步(六)——经典魔术《傅氏幻术》赏析和《我的心灵感应》...
- Moonriver Network与Calamari Network完成XCM集成
- 如何添加Google统计在自己的网站