Lex与Yacc学习(三)之符号表

符号表

列举单词表的方式虽然简单但是不全面,如果在词法分析程序运行时可以构建一个单词表,那么就可以在添加新的单词时不用修改词法分析程序。

下面示例便利用符号表实现,即在词法分析程序运行时从输入文件中读取声明的单词时允许动态的声明单词。声明以词性的名字开始,后面跟着要声明的单词。

添加符号表可以完全的改变词法分析程序,不必在词法分析程为每个要匹配的单词放置独立的模式,只要有一个匹配任意单词的模式,再查阅符号表就能决定所找到的词性。

lex程序ch1-04.l

%{
  /*
   *带符号表的词法分析程序
   */

   enum{
		LOOKUP = 0, /*默认——查找而不是定义*/
		VERB,
		ADJ,
		ADV,
		NOUN,
		PREP,
		PRON,
		CONJ
	};

	int state;
	int add_word(int type, char *word);
	int lookup_word(char *word);
%}

%%
\n		{state = LOOKUP;} /*行结束,返回到默认状态*/

		/*无论何时,行都以保留字的词性名字开始*/
		/*定义该类型的单词*/
^verb 	{state = VERB;}
^adj	{state = ADJ;}
^adv	{state = ADV;}
^noun	{state = NOUN;}
^prep	{state = PREP;}
^pron	{state = PRON;}
^conj	{state = CONJ;}

[a-zA-Z]+	{
				/*一个标准的单词、定义或者查找它*/
				if(state != LOOKUP){
					/*定义当前单词*/
					add_word(state,yytext);
				}else{
					switch(lookup_word(yytext)){
						case VERB: printf("%s: verb\n",yytext); break;
						case ADJ: printf("%s: adj\n",yytext); break;
						case ADV: printf("%s: adv\n",yytext); break;
						case NOUN: printf("%s: noun\n",yytext); break;
						case PREP: printf("%s: prep\n",yytext); break;
						case PRON: printf("%s: pron\n",yytext); break;
						case CONJ: printf("%s: conj\n",yytext); break;
						default:
									printf("%s: don't recognize\n",yytext);
									break;
					}//switch
				}//else
			}
			/*忽略其他的东西*/
%%

int main()
{
	yylex();
}

/*定义一个连接的单词和类型列表*/
struct word{
	char *word_name;
	int word_type;
	struct word *next;
};

struct word *word_list; //first element in 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;
	}//if

	/*单词不在那里,分配一个新的条目并将它连接到列表上*/
	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;
	}//for
	return LOOKUP;
}

int yywrap()
{
	return 1;
}

运行命令及结果:

程序代码说明:

在上述lex词法分析程序中,add_word()表示在符号表中放置一个新的单词;

lookup_word()表示查询已经输入的单词。

在程序代码中,声明一个变量state,用来记录是在查找单词(状态LOOKUP)还是在声明它们(在这种情况下,state能记住我们正在声明的单词种类)。

无论何时,只要我们看到以词性名字开始的行,就可以将状态设置为声明单词的种类;每次看到\n时就都切换回正常的查找状态。

时间: 2024-08-29 00:08:38

Lex与Yacc学习(三)之符号表的相关文章

前端学习(9)~css学习(三):样式表和选择器

本文主要内容 CSS概述 CSS和HTML结合的三种方式:行内样式表.内嵌样式表.外部样式表 CSS四种基本选择器:标签选择器.类选择器.ID选择器.通用选择器 CSS几种扩展选择器:后代选择器.交集选择器.并集选择器 CSS样式优先级 CSS 概述 CSS:Cascading Style Sheet,层叠样式表.CSS的作用就是给HTML页面标签添加各种样式,定义网页的显示效果.简单一句话:CSS将网页内容和显示样式进行分离,提高了显示功能. css的最新版本是css3,我们目前学习的是css

Lex与Yacc学习(一)之环境配置篇

Abstract 在开发程序的过程中经常会遇到文本解析的问题,例如:解析 C 语言源程序,编写 脚本引擎等等,解决这种文本解析的方法有很多,一种方法就是自己手动用 C 或者 C++直接编写解析程序,这对于简单格式的文本信息来说,不会是什么问题,但是 对于稍微复杂一点的文本信息的解析来说,手工编写解析器将会是一件漫长痛苦 而容易出错的事情.本系列文档就是专门用来由浅入深的介绍两个有名的 Unix 工 具 Lex 和 Yacc,并会一步一步的详细解释如何用这两个工具来实现我们想要的任何 功能的解析程

Lex与Yacc学习(四)之Lex规范

Lex规范的结构 lex程序由三部分组成:定义段.规则段和用户子例程序段 ...定义段... %% ...规则段... %% ...用户子例程序段... 这些部分由以两个百分号组成的行分隔开.尽管某一部分可以为空,但前两部分是必须的,第三部分和前面的%%行可以忽略. 定义段 定义段包括文字块.定义.内部表声明.起始条件和转换. 以空白开头的行被逐字拷贝到C文件中,通常,这用于包含包围在/*和*/中的注释,一般前面有空白. 规则段 规则段包含模式行和C代码,以空白开始的行或者包围在%{和%}中的内

Lex与Yacc学习(九)之Yacc语法

Yacc语法 本文讨论yacc语法的格式并描述可用的各种特征和选项 yacc语法结构 yacc语法包括三部分:定义段.规则段和用户子例程段 ...定义段... %% ...规则段... %% ...用户子例程段... 各部分由以两个百分号开头的行分开,尽管某一个部分可以为空,但是前两部分是必须的,第三部分和前面的百分号可以省略. 符号 yacc 语法由符号组成,即语法的"词".符号是一串不以数字开头的字母.数字.句点和下划线.符号error专用于错误恢复,另外,yacc对任何符号都不会

Lex与Yacc学习(五)之正则表达式篇

正则表达式语法 lex模式是由编辑程序和实用程序使用的正则表达式的扩展版本.正则表达式由常规字符(代表它们本身)和元字符(在一种模式中具有特殊含义)组成. 元字符 . . 匹配除了换行符 \n 之外的任意单个字符 [] [] 匹配括号中字符的任意一个.用"-"(短划线)指示字符的范围,例如[0-9]指10个数字中的任意一个.如果开括号之后的第一个字符是短划线或者闭括号,那么它就不能被解释为元字符.如果第一个字符是抑扬字符" ^ ",那么它的含义就变为匹配括号内字符以

Lex与Yacc学习(八)之变量和有类型的标记(扩展计算器)

变量和有类型的标记 下一步扩展计算器来处理具有单个字母名字的变量,因为只有26个字母 (目前只关心小写字母),所以我们能在26个条目的数组(称它为vbltable)中存储变量. 为了使得计算器更加有用,也可以扩展它来处理多个表达式(每行一个)和使用浮点值. 具有变量和实值的计算器词法ch3-03.l %{ #include "ch3-03.tab.h" #include <math.h> extern double vbltable[26]; %} %% ([0-9]+|(

Lex与Yacc学习(七)之环境配置另一种方式

必备工具 flex-2.5.4a-1.exe   和  bison-2.4.1-setup.exe   以及 cygwin2.738 的安装文件,下载地址 http://download.csdn.net/detail/fly_yr/8385245 flex与bison安装 运行flex-2.5.4a-1.exe  和  bison-2.4.1-setup.exe 文件安装至D:\Software Files\GnuWin32下,然后按配置环境变量: 将路径 D:\Software Files\

Android so注入(inject)和Hook技术学习(三)——Got表hook之导出表hook

前文介绍了导入表hook,现在来说下导出表的hook.导出表的hook的流程如下.1.获取动态库基值 1 void* get_module_base(pid_t pid, const char* module_name){ 2 FILE* fp; 3 long addr = 0; 4 char* pch; 5 char filename[32]; 6 char line[1024]; 7 8 // 格式化字符串得到 "/proc/pid/maps" 9 if(pid < 0){

Oracle 学习(三)多表联查

目录 Oracle 学习(三)多表联查 一.99语法 二.至少两种方式行转列 三.分页 Oracle 学习(三)多表联查 @ 一.99语法 Oracle学习(二)中我们学习了92语法,现在我们学习一下99语法 sql 1999语法 1.1.cross join 笛卡尔积 select * from emp cross join dept; 1.2.natural join 自然连接 当两个表不具有相同列名,进行cross join,具有相同列名,自动匹配 select * from emp e