⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scanner.l

📁 《编译方法》课程设计内容2.《编译方法》课程设计内容
💻 L
字号:
%{
/******************************************************************************
******************************************************************************* 
 
                                   scanner.l

			        词法分析lex源文件
			     
   本文件定义了VSL语言的词法,及词汇处理函数。

   文件修改时间
   ============

   2005年5月6日:  Lex源文件 (C) hfwang
  
*******************************************************************************
******************************************************************************/

/* 定义部分 */

/* 以下是词法分析器需要的头文件和函数的引用说明,mkxxx()将识别的词形放入符号表
   中,全局变量lineno记录当前行号,在词法和语法分析出错时,可输出错误所在的行,
   以方便对程序的修改 */

#include <stdio.h>
#include <ctype.h>
#include <string.h>

#include "vc.h"
#include "parser.h"   	/* 由yacc生成的词汇的宏定义其语义值的数据类型 */

void  mkname( void ) ;
void  mkval( void ) ;
void  mktext( void ) ;		/* 函数的定义在本文件的代码部分 */

int lineno = 1;

/* 以下定义一组正规表达式,以方便对各种词汇的处理。由于是通过换行符"\n"来记录
   行号,我们对它单独处理,所以分界符delimiter和空白字符whitespace中没有"\n"。
   VSL语言的词法规定关键字一律用大写字母表示,而标识符一律用小写字母表示,在
   此定义un_letter表示大写字母,lc_letter表示小写字母,VSL的注释由双斜杠//直
   到第一个环行符\n之前结束;VSL的常数只有正数常数,在此由integer定义;VSL的
   标识符是以小写字母开始并由小写字母和数字组成的字符串,其长度没有限制,在此
   由variable定义,VSL的字符串中允许有转义字符"\""和"\n"(定义为espaced_char),
   分别表示字符双引号"和换行,在此由text定义。 */

%}

comment		"//".*
delimiter	[ \t]
whitespace	{delimiter}+
uc_letter	[A-Z]
lc_letter	[a-z]
letter		{lc_letter}|{uc_letter}
ascii_char	[^\"\n]
escaped_char	\\n|\\\"
digit		[0-9]
variable	{lc_letter}({lc_letter}|{digit})*
integer		{digit}+
text		\"({ascii_char}|{escaped_char})*\"

%%

%{
/* 规则部分 */  

/* 在规则部分定义了VSL的词汇的模式及再识别词汇后对应的C操作,对注释和空白字符
   yylex不做任何操作,即相当于吃掉这些字符,继续执行yylex,对换行符"\n",其唯
   一的操作是行计数器加1,对标识符,常正数和字符串常量,我们首先将识别的词形或
   对应的数值放入符号表中,并定义其语义值yylval为在符号表的指针,再返回其对应
   的词汇编码给调用它的语法分析函数yyparse()。对关键字,只是简单地返回其对应的
   词汇码,对于单个的字符,由于在语义分析中其词汇码就是该字符对应的ASCII码,所
   以返回该字符yytext[0]即可。在匹配词形后的操作中如果有return语句,则表示结束
   yylex()函数,但是,yylex()的环境保持不变(如扫描文件的文件指针),下次再调
   用时,yylex()继续扫描输入文件还未扫描的字符。
*/
%}

{comment}	; { }
{whitespace}	; { }
\n		{ lineno++; }
{variable}	{ mkname();
		  return VARIABLE; }
{integer}	{ mkval();
		  return INTEGER;}
{text}          { mktext();
		  return TEXT;}
":="		{ return ASSIGN_SYMBOL;}
FUNC		{ return FUNC;}
PRINT 		{ return PRINT;}
RETURN 		{ return RETURN;}
CONTINUE	{ return CONTINUE;}
IF 		{ return IF;}
THEN 		{ return THEN;}
ELSE		{ return ELSE;}
FI 		{ return FI;}
WHILE 		{ return WHILE;}
DO 		{ return DO;}
DONE 		{ return DONE;}
VAR 		{ return VAR;}
.		{ return yytext[0]; }


%%

/* 代码部分 */

/* 在识别一个标识符、正数和字符串常量后,通过以下的mkxxx()将其装入符号表中,并
   将符号指针作为该终结符的语义值(全局变量yylval)。*/

void mkname ( void )

/* 创建标识符函数,在词法分析程序匹配一个标识符之后,虽然指向该标识符的指针
   yytext是全局变量,但是保存该标识符的字符数组是局部变量,即在yylex函数返回
   之后不再可使用,因此在保存标识符时,必须通过动态申请同该标识符长度相同的
   内存来存放该标识符,只有这样该标识符才能被整个编译器使用。*/

{
	struct symb *t;
	char	    *s;

	/* 首先查看符号表,如果该标识符已在符号表中,则表明当前标识符不是首
           次出现,我们将yylval设为该标识符在符号表的指针并返回即可 */

	if((t = lookup(yytext)) != NULL)
	{
		yylval.symb = t;
		return;
	}

	s = (char *) safe_malloc(yyleng + 1); 	/* 申请备份的内存,全局变量
						   yyleng是当前词形的长度  */
	
	strncpy(s, yytext, yyleng); 		/* 安全字符串考拷贝 */
	s[yyleng] = EOS;

	t	 = get_symb();			/* 创建符号内存单元 */

	t->type  = T_UNDEF;			/* 定义符号单元 */
	t->TEXT1 = s;

	insert(t);				/* 插入符号表 */

	yylval.symb = t;			/* 设置语义值 */

} 	/* void mkname ( void ) 结束 */


void mkval( void )

/* 创建正数常量:通过库函数atoi()将识别的正数字符串转换为对应的正数,调用mkconst()
   对该整数创建一个符号内存单元并将之放入符号表中,设置语义值为该符号指针。 */

{
	yylval.symb = mkconst( atoi( yytext ));

}	/* void mkval( void ) 结束 */

void mktext( void )

/* 创建字符串常量:用mkname()对识别的字符串创建一个符号内存单元(注意:该字符串的首尾
   是双引号",并有转义字符,因此,在代码生成中对字符串分配内存时,一定要将双引号除掉,
   并将转义字符转换成相应的ASCII码),设置字符串的符号属性,在此,我们使用标号来记录
   字符串的地址,标号计数器next_label分配一个标号后加1。*/
{
	mkname();
	yylval.symb->type = T_TEXT;
	yylval.symb->VAL2 = next_label++;

}	/* void mktext( void ) 结束 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -