编译原理实验

时间:2024-05-20 09:07:03

一、实验目的

  1. 学习使用词法分析程序自动构造工具 Flex

  2. 熟悉LEX源程序语法

  3. 掌握词法分析程序的自动构造方法
    二、实验平台
    Windows + Flex
    三、基础内容

  4. 实现以下步骤, 掌握Flex的工作过程
    i. 构造 LEX 源程序, 例如命名为 Test.Lex
    ii. 编译 LEX 源程序, 生成C语言词法分析程序 lex.yy.c, 步骤如下:
    在DOS命令提示符下执行编译 flex Test.Lex 得到目标文件 lex.yy.c
    iii. 在VC中编译 lex.yy.c,产生可执行程序 lex.yy.exe
    iv. 运行生成的可执行文件 lex.yy 或 lex.yy < InputFile

  5. 测试目录 SRC_FLEX中的范例程序,了解其功能及实现。

四、附加内容
★★ 输入一个 C源程序文件, 用FLex 实现以下任务
a) 添加行号。
b) 将文件中每个非空的空白符号序列替换为单个空格。
c) 将文件中所有关键字转换为大写字母。
d) 将文件中所有标识符转换为小写字母,且以下划线开头。
e) 将文件中所有指数形式的常量转换为小数形式。
例如: 2.5e3 被转换为 2500
3.7e-2 被转换为 0.037
f) 将转换后的文件存入另一个文件。

参考资料

  1. LEX范例程序:SRC_FLEX

b.lex文件如下:


%{
     #include <stdio.h>
     FILE *f1;
     FILE *f2;
     int hanghao=2;
%}
 
keyword  auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while|AUTO|BREAK|CASE|CHAR|CONST|CONTINUE|DEFAULT|DO|DOUBLE|ELSE|ENUM|EXTERN|FLOAT|FOR|GOTO|IF|INT|LONG|REGISTER|RETURN|SHORT|SIGNED|SIZEOF|STATIC|STRUCT|SWITCH|TYPEDEF|UNION|UNSIGNED|VOID|VOLATILE|WHILE
id       [A-Za-z]+
digit    [0-9]
huan     {digit}+(\.{digit}+)?(E[+-]?{digit}+)?
 
%%
 
[ ]+     {fprintf(f1," ");}
 
\n 	{fprintf(f1,"%s%u",yytext,hanghao++);}
 
{keyword} {
               int i;
               for(i=0;i<yyleng;i++)
               {
                   if(yytext[i]>='a'&&yytext[i]<='z')
                      yytext[i]-=32;
                }
                fprintf(f1,"%s",yytext);
           }
 
 
{id}      {
               int i;
               for(i=0;i<yyleng;i++)
               {
                    if(yytext[i]>='A'&&yytext[i]<='Z')
                      yytext[i]+=32;
                }
                fprintf(f1,"_%s",yytext);
           }
 
 
{huan}     {   float  t=0;
               t=atof(yytext);
               fprintf(f1,"%f",t);
           }
.        fprintf(f1,"%s",yytext);
%%
 
int yywrap(void)
{
     return 1;
}
 
main()
{
    f1=fopen("f1.txt","w+");
    fprintf(f1,"1");
    yylex();
    fclose(f1);
    f1=fopen("f1.txt","r");
    f2=fopen("f2.txt","w");
    char e;
    while((e=fgetc(f1) )!= EOF )
    {fputc(e,f2);}
    fclose(f1);
    fclose(f2);
}


一、实验目的

  1. 学习使用词法分析程序自动构造工具Flex

  2. 熟悉LEX源程序语法

  3. 掌握词法分析程序的自动构造方法

二、实验平台
Windows+ Flex

三、基础内容

  1. 实现以下步骤, 掌握Flex的工作过程

i. 构造 LEX 源程序, 例如命名为 Test.Lex

ii. 编译 LEX 源程序, 生成 C 语言词法分析程序 lex.yy.c, 步骤如下:

在 DOS 命令提示符下执行编译 flex Test.Lex 得到目标文件 lex.yy.c iii. 在 VC 中编译lex.yy.c,产生可执行程序lex.yy.exe

iv. 运行生成的可执行文件 lex.yy 或 lex.yy < InputFile

  1. 测试目录SRC_FLEX中的范例程序,了解其功能及实现。

四、附加内容
输入一个 C 源程序文件, 用 FLex 实现以下任务

a) 添加行号。

b) 将文件中每个非空的空白符号序列替换为单个空格。

c) 将文件中所有关键字转换为大写字母。

d) 将文件中所有标识符转换为小写字母,且以下划线开头。

e) 将文件中所有指数形式的常量转换为小数形式。

例如: 2.5e3被转换为 2500 3.7e-2 被转换为 0.037 f) 将转换后的文件存入另一个文件。

声明部分

%%

转换规则

%%

辅助函数

Lex程序的每个转换规则的形式如下:

模式{动作}

%{%} 括号中间的所有内容将直接复制到lex.yy.c中。

一个lex程序的结构如下:

yytext 是一个指向词素开头的指针
yyleng存放刚找到的词素的长度
源代码:
Demo.lex

%{
#include<stdio.h>
FILE* f1;
int n =1;
%}
 
keywords auto|break|case|char|const|continue|defaultdo|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while
id [a-zA-Z][a-zA-Z0-9]*
number [0-9]
enumber {number}+(\.{number}+)?e([+-])?{number}+
space [\ \t]+
 
%%
 
{space} {fprintf(f1," ");}
 
{keywords} {
		int i = 0;
		while(i<yyleng && yytext[i]>='a' && yytext[i]<='z')
		{
		yytext[i]-=32;
		i++;
	   	 }
		fprintf(f1,"%s",yytext);
		}
 
{id} {
	int i =0 ;
	while(i<yyleng && yytext[i]>='A' && yytext[i]<='Z')
	{
	yytext[i]+=32;
		i++;	
	}
	fprintf(f1,"_%s",yytext);
	}
 
{enumber} {
	float f = atof(yytext);	
	fprintf(f1,"%f",f);	
}
 
[^\n] {fprintf(f1,"%s",yytext);}
\n {
	fprintf(f1,"%s%5d  ",yytext,n++);
	}
 
%%
 
int yywrap(void)
{
  return 1;
}
 
main()
{
  f1 = fopen("demo.txt","a+");
  fprintf(f1,"%5d  ",n++);
  yylex();
  fprintf(f1,"\n");
  fclose(f1);
}

运行:

编译原理实验

将生成的lex.yy.c编译

用lex.yy.exe 打开一个文件
编译原理实验

规则化的文件:
编译原理实验