(一):写在前面


在上面的学习当中,我们通过简单的lex例子,进一步扩展lex例子,通过和yacc的融合来进行简单英语语法分析。通过这几个例子,使我们深深的感受到lex和yacc的方便和强大功能。我们最终的目标是通过学习使用lex和yacc来实现一个简单的shell解释器,估计借用lex和yacc力量,我们的shell命令解释器实现起来就非常简单了。

(二):英语简单语法分析扩展


在这里我们通过对上一小节中的英语句型分析程序的扩展,实现简单复合语句的分析。

我们来看一下我们的程序源码:

文件名:ch05.lex

%{/** 现在我们构建一个有高级语法分析程序使用的词法分析程序*/#include "y.tab.h"#define LOOKUP 0 /* 默认情况 - 不是一个定义的单词类型 */int state;%}%%\n { state = LOOKUP; }\.\n { state = LOOKUP;return 0; /* 句子结尾 */}^verb { state = VERB; }^adj { state = ADJECTIVE; }^adv { state = ADVERB; }^noun { state = NOUN; }^prep { state = PREPOSITION; }^pron { state = PRONOUN; }^conj { state = CONJUNCTION; }[a-zA-Z]+ {if(state != LOOKUP){add_word(state,yytext);}else{switch(lookup_word(yytext)){case VERB:return(VERB);case ADJECTIVE:return(ADJECTIVE);case ADVERB:return(ADVERB);case NOUN:return(NOUN);case PREPOSITION:return(PREPOSITION);case PRONOUN:return(PRONOUN);case CONJUNCTION:return(CONJUNCTION);default:printf("%s: don't recognize\n",yytext);/* 不反悔,忽略 */}}}. ;%%/* 定义一个单词和类型的链表 */struct word{char *word_name;int word_type;struct word *next;};struct word *word_list;  /* 单词链表中的第一个元素 */extern void *malloc();int add_word(int type,char *word){struct word *wp;if(lookup_word(word) != LOOKUP){printf("!!warning:word %s already defined\n",word);return 0;}/* 单词不在那里,分配一个新的条目并将他连接到链表上 */wp = (struct word *)malloc(sizeof(struct word));wp->next = word_list;/* 还必须复制单词本身 */wp->word_name = (char *)malloc(strlen(word)+1);strcpy(wp->word_name,word);wp->word_type = type;word_list = wp;return 1;  /* 成功添加 */}int lookup_word(char *word){struct word *wp = word_list;/* 向下搜索列表以寻找单词 */for(;wp;wp = wp->next){if(strcmp(wp->word_name,word) == 0)return wp->word_type;}return LOOKUP;}int yywrap(){return 1;}

在这个程序当中,和上一个小节中的内容是差不多的,主要是将相应词性的词语放到一个链表当中,便于查找。

下面我们来看一下yacc文件中的定义。

文件名:ch05.y

%{#include <stdio.h>/* We found the following required for some yacc implementations *//* #define YYSTYPE int */%}%token NOUN PRONOUN VERB ADVERB ADJECTIVE PREPOSITION CONJUNCTION%%sentence: simple_sentence { printf("Parsed a simple sentence.\n"); }| compound_sentence { printf("Parsed a compound sentence.\n"); };simple_sentence: subject verb object| subject verb object pre_phrase;compound_sentence: simple_sentence CONJUNCTION simple_sentence| compound_sentence CONJUNCTION simple_sentence;subject: NOUN| PRONOUN| ADJECTIVE subject;verb: VERB| ADVERB VERB| verb VERB;object: NOUN| ADJECTIVE object;pre_phrase: PREPOSITION NOUN;%%extern FILE *yyin;int main(){yyparse();while(!feof(yyin)){yyparse();}return 0;}yyerror(s)char *s;{fprintf(stderr,"%s\n",s);}

在这里,我们添加了一些符合语句的分析语法。

sentence: simple_sentence { printf("Parsed a simple sentence.\n"); }| compound_sentence { printf("Parsed a compound sentence.\n"); };simple_sentence: subject verb object| subject verb object pre_phrase;compound_sentence: simple_sentence CONJUNCTION simple_sentence| compound_sentence CONJUNCTION simple_sentence;

我们来看一下这几行代码:

在上一节中,我们了解到,yacc中,越靠上的规则,其优先级越高。所以,上面的sentence规则定义了是一个简单的语句,而该简单的语句simple_sentence又在下面定义了规则subject verb object,通过这两个规则,我们定义了简单语句。

然后通过简单语句的组合又定义了复合语句,这个可以通过我们的第三条规则来看出来。

下面我们来定义一下用于编译的Makefile文件:

Makefile

all:lex ch05.lexyacc -d ch05.ygcc -c lex.yy.c y.tab.cgcc -o hello lex.yy.o y.tab.o -llclean:rm lex.yy.o y.tab.o lex.yy.c y.tab.c y.tab.h hello

接着使用命令make来编译该程序,编译完成之后,我们来看一下当前目录:

.
├── ch05.lex
├── ch05.y
├── hello
├── lex.yy.c
├── lex.yy.o
├── Makefile
├── y.tab.c
├── y.tab.h
└── y.tab.o0 directories, 9 files

现在我们来运行一下刚刚我们编译的程序,使用下面的命令来运行该程序:

    ./hello

(三):lex和手写的词法分析程序


下面我们通过使用lex编写一个词法分析程序和使用C语言编写词法分析程序的比较,来提高我们对lex和yacc的方便性,全面性,整体性的认识。

首先,我们先看一下使用C语言编写的简单词法分析程序,该程序用来处理命令,数字,字符串和换行,忽略注释和空白的。我们来看一下:

#include <stdio.h>#include <ctype.h>#define NUMBER 400#define COMMENT 401#define TEXT 402#define COMMAND 403int main(int argc,char **argv){int val;while(val = lexer())printf("value is %d.\n",val);return 0;}int lexer(){int c;while((c = getchar()) == ' ' || c == '\t');if(c == EOF)return 0;if(c == '.' || isdigit(c)) /* 数字 */{while((c = getchar()) != EOF && isdigit(c));ungetc(c,stdin);return NUMBER;}if(c == '#') /* 注释 */{int index = 1;while((c = getchar()) != EOF && c != '\n');ungetc(c,stdin);return COMMENT;}if(c == '"') /* 字符串 */{int index = 1;while((c = getchar()) != EOF && c != '"' && c != '\n');if(c == '\n')ungetc(c,stdin);return TEXT;}if(isalpha(c)) /* 命令 */{int index = 1;while((c = getchar()) != EOF && isalnum(c));ungetc(c,stdin);return COMMAND;}return c;}

这个大家可以编译一下,运行起来看看效果,这里我们就不编译运行了,因为我们主要是为了对比他们的区别。

下面我们来看一下lex编写的词法分析程序:

%{#define NUMBER 400#define COMMENT 401#define TEXT 402#define COMMAND 403%}%%[ \t]+  ;[0-9]+  |[0-9]+\.[0-9]+  |\.[0-9]+    { return NUMBER; }#.* { return COMMENT; }\"[^\"\n]\" { return TEXT; }[a-zA-Z][a-zA-Z0-9]+    { return COMMAND; }\n  { return '\n'; }%%#include <stdio.h>int main(int argc,char **argv){int val;while(val = yylex())printf("value is %d\n",val);return 0;}int yywrap(){return 1;}

很明显,长度上lex版本是C词法分析程序的三分之一。我们的经验是程序中的错误数一般与他的长度成正比,我们估计词法分析程序的C版本要花三倍的时间来编写和排除错误。

同时,使用C编写的词法分析程序有一个明显的错误,就是注释有两颗星的时候,就意味着注释失败:

/** 注释 **/

所以说,使用C实现的词法分析程序可能会有一些想不到的错误。

(四):写在后面


在下面的小节中,我们将更深入的研究lex,yacc的使用,以及lex和yacc混合使用方式,来实现更加复杂的词语法分析。

转载于:https://www.cnblogs.com/bobo1223/p/7287474.html

纯C实现的词法分析和lex实现的词法分析的对比相关推荐

  1. 《编译与反编译技术实战》——1.2 词法分析生成器LEX

    本节书摘来自华章计算机<编译与反编译技术实战>一书中的第1章,第1.2节,作者 刘晓楠 陶红伟 岳峰 戴超,更多章节内容可以访问云栖社区"华章计算机"公众号查看. 1. ...

  2. 编译原理:用lex/flex做词法分析

    最近在自学<编译原理>,感觉对于我来说有点难度. 写这个的目的是为了做笔记,感谢https://blog.csdn.net/xiaowei_cqu/article/details/7760 ...

  3. 词法分析程序 LEX和VC6整合使用的一个简单例子

    词法分析的理论知识不少,包括了正规式.正规文法.它们之间的转换以及确定的有穷自动机和不确定的有穷自动机等等... 要自己写一个词法分析器也不会很难,只要给出了最简的有穷自动机,就能很方便实现了,用if ...

  4. lex 词法分析 linux,lex语言词法分析

    1.添加行号 %{ #include #include int line=1; %} %% [^\n] {yymore();} [\n] {printf("%2d %s",line ...

  5. lex编译dos命令_lex.yy.c如何运行

    ? FLEX 1.L 3.运行 FLEX 后,产生"LEXYY.C"程序 4 .用 VC 打开"LEXYY.C" 程序,编译后产生"LEXYY.EXE ...

  6. 使用Lex工具进行tiny+语言的词法分析

    词法分析程序实验报告 实验环境 架构:Intel x86_64 (虚拟机) 操作系统:Ubuntu 20.04 汇编器:gas (GNU Assembler) in AT&T mode 编译器 ...

  7. 【编译原理】 实验一:词法分析器的自动实现(Lex词法分析)

    一.实验内容 1.借助词法分析工具Flex或Lex完成(参考网络资源) 2.输入:高级语言源代码(如helloworld.c) 3.输出:以二元组表示的单词符号序列. 二.实验目的 通过设计.编制.调 ...

  8. 关于《利用Lex进行词法分析》

    利用Lex进行词法分析 写在前面 目前开展编译原理这门课程,许多同学说实话学不到什么东西,知识一昧地做题,我个人是不建议的.当我看到课本上有一页是来介绍利用Lex和Yacc做词法分析和语法分析的时候, ...

  9. LEX和YACC的使用

     Lex自动地表示把输入串词法结构的正规式及相应的动作转换成一个宿主语言的程序,即词法分析程序,它有一个固定的名字yyler,在这里yyler是一个C语言的程序. Yylex将识别出输入串中的词形 ...

  10. c++自底向上算符优先分析_词法分析程序的自动生成器(二)——Thompson算法

    碎碎念:我写词法分析程序的自动生成器的时候,先写的NFA-DFA和DFA化简.之后发现因为正则表达式的结构太复杂了,比如描述Pl/0程序标识符的正则表达式是 (a|-|z|A|-|Z)( a|-|z| ...

最新文章

  1. 梯度下降原理及Python实现
  2. quick-cocos2dx-2.2.4环境搭建
  3. 支持插件的消息中间件【msg broker with plugin】 - 知然 - 博客园
  4. java定时任务,每天定时执行任务
  5. php阿里云oss文件上传
  6. MongoDB学习之(一)安装
  7. Windows 9信息曝光:统一开发接口、整合Cortana到任务栏
  8. 陌陌宣布启用全新中文名“挚文集团” ,Q2净利润4.6亿元
  9. 字符变量赋值规则_第四章 变量
  10. Tosca:键盘输入字符串
  11. 数据集中异常值的处理之lof,iforest算法
  12. 计算机 会议录用率 统计
  13. 电子设计大赛-信号源类题目分析
  14. 2022低压电工考试题库模拟考试平台操作
  15. ae渲染出现错误是什么问题_AE渲染输出总是损坏怎么办-解决AE渲染输出被损坏的方法 - 河东软件园...
  16. 将RT-Thread Nano移植到STM32F401CCU6
  17. android 异常 android Removing unused resources requires unused code shrinking to be turned on.
  18. 菜鸟日记(yzy):opencMS系统-XML内容管理文件开发
  19. mysql notifier什么_MySQLNotifier这个东西有什么作用?
  20. 前端--CSS选择器,盒子模型学习

热门文章

  1. atitit.图片相似度与图片查找的设计 获取图片指纹
  2. atitit.基于虚拟机的启动器设计 --java 启动器 java生成exe
  3. paip.提升程序稳定性---最佳实践
  4. 流程机器人 RPA:AI落地的接盘侠 | 甲子光年
  5. 何波: 程序化交易系统构建与风险控制
  6. 农业银行王敬东——金融科技时代商业银行战略模式选择初探
  7. (转)李嘉诚:成功源于花90%时间考虑失败
  8. Rust : CSV库的用法
  9. 2022美国大学生数学建模竞赛D题思路
  10. 【图像隐写】基于matlab DWT+DCT+LSB数字水印隐藏提取比较【含Matlab源码 1623期】