编译原理实验一之词法分析

一、实验目的

设计实现一个词法分析程序,加深对词法分析原理的理解

二、实验仪器

Visual studio

三、实验内容及原理

(1)设一小型编译程序关于高级语言有如下的规定: 

高级语言程序具有四种基本结构:顺序结构﹑选择结构﹑循环结构和过程。为了便于掌握编译的核心内容,突出重点,简化编译程序的结构,同时又涵盖高级语言程序的基本结构,我们选取赋值语句﹑if语句和while语句作为前三种结构的代表,略去了过程结构。实际上,上述三种语句已经基本满足了高级语言的程序设计。因此,我们仅考虑由下面产生式所定义的程序语句:

Sif B then S else S while B do S begin L endA

LS;LS

Ai:=E

BBBBB¬ B(B) i rop ii

EE+EE*E(E) i

其中,各非终结符的含义如下:

S——语句;

L——语句串;

A——赋值句;

B——布尔表达式;

E——算术表达式。

各终结符的含义如下:

i ——整型变量或常数,布尔变量或常数;

rop ——六种关系运算符的代表;

 ; ——起语句分隔符作用;

 := ——赋值符号;

¬ ——逻辑非运算符“not”

 ——逻辑与运算符“and”

∨ ——逻辑或运算符“or”

+ ——算术加运算符;

* ——算术乘运算符;

( ——左括号;

) ——右括号。

注意,六种关系运算符分别为

     <:小于      <=:小于等于     <>:不等于

     >:大于      >=:大于等于      =:等于

关于表达式的运算,我们规定由高到低优先顺序为算术运算、关系运算、布尔运算;并且服丛左结合规则。算术运算符优先级的顺序依次为“( )”“*” “+” ;布尔运算符优先级的顺序依次为“¬ ”;六个关系运算符优先级相同。

我们规定的程序是由一条语句或由beginend嵌套起来的复合语句组成的,并且规定在语句末要加上“#~”表示程序结束。下面给出的是符合规定的程序示例:

    begin

    A:=A+B*C;

    C:=A+2;

    while A<C and B<D do

            while A>B do

                 if M=N then C:=D

            else while A<=D do

                  A:=D

     end#~

(2)该小型编译程序关于单词的内部定义 

由于我们规定的程序语句中涉及单词较少,故在词法分析阶段忽略了单词输入错误的检查,而将编译程序的重点放在中间代码生成阶段。词法分析器的功能是输入源程序,输出单词符号。我们规定输出的单词符号格式为如下的二元式:(单词种别,单词自身的值)

我们对常量,变量,临时变量,保留关键字(ifwhilebeginendelsethendo),关系运算符,逻辑运算符,分号,括号等,规定其内部定义如表1所示。

1  关于单词的内部定义

实验要求:

请对下列程序进行词法分析,输出单词的种别编码和值:

begin
    begin
   
        begin 
         a:=1
         end;
         
       begin 
         b:=1
    end;
    q:=10
    end;
    
    x:=9;
    y:=11;
    z:=12
end
#

四、实验过程原始数据记录

主要结构:

typedef struct //词的结构(单词种别,单词自身的值)

{

int typenum; //单词种别

const char* word;

}WORD;

主要函数:

char get_ch()   从输入缓冲区读取一个字符到ch中

void removal_White( )     去掉空白字符

void concat( )     拼接单词

int letter( )       判断输入字符是否是字母

int digit( )        判断输入字符是否是数字

int reserve( )     检索关键字表格,判断单词是否为关键字

void retract( )     回退一个字符

WORD * scanner( )  词法扫描程序,返回值是二元组

结果:

五、实验总结

在进行编译的时候,有出现编译错误:

编译出错信息:错误    1    error C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.  

后来我上网查询了一下,意思就是fopen不安全,推荐你用fopen_s。

解决上面问题后,我成功运行,但在运行时又实验结果出现了偏差

我后来在不同地方的错误提示增加区别,找到了错误提示的地方在词法扫描时的Switch语句。

这意味着我在消除空白即消除换行空字符时没有处理好,我在编辑data.txt发现是tab空格没有消除

于是在去除空白的函数removal_White()加上ch==9的情况。最后成功运行并输出单词的种别编码和值

实验代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define _CRT_SECURE_NO_WARNINGS
#define _KEY_WORDEND "waiting for your expanding"
using namespace std;
typedef struct //词的结构(单词种别,单词自身的值)
{
	int typenum; //单词种别
	const char* word;
}WORD;
char input[255];
char token[255] = "";
int p_input; //指针
int p_token;
char ch;
const char* rwtab[] = { "if","then","else","while","begin","do","end","and","or","not","S","L",_KEY_WORDEND};

WORD* scanner();//扫描

int main()
{
	int over = 1;
	WORD* oneword = new WORD;

	//实现从文件读取代码段
	FILE* fp;
	if ((fp = freopen("data.txt", "r", stdin)) == NULL)
	{
		printf("Not found file!\n");
		return 0;
	}
	else
	{
		while ((scanf("%[^*]", &input)) != EOF)
		{
			p_input = 0;
			printf("your words:\n%s\n", input);
			while (over < 1000 && over != -1)
			{
				oneword = scanner();
				if (oneword->typenum < 1000)
				{
					if (oneword->typenum != 999)
						cout << "[  " << oneword->typenum << "\t" << oneword->word << "  ]" << endl;
				}
				over = oneword->typenum;
			}
			scanf("%[^*]", input);
		}
	}
	return 0;
}

//从输入缓冲区读取一个字符到ch中
char get_ch()
{
	ch = input[p_input];
	p_input++;
	return ch;
}

//去掉空白
void removal_White()
{
	while (ch == ' ' || ch == 10 || ch == 9)
	{
		ch = input[p_input];
		p_input++;
	}
}

//拼接单词
void concat()
{
	token[p_token] = ch;
	p_token++;
	token[p_token] = '\0';
}

//判断是否字母
int letter()
{
	if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z')
		return 1;
	else
		return 0;
}

//判断是否数字
int digit()
{
	if (ch >= '0' && ch <= '9')
		return 1;
	else
		return 0;
}

//检索关键字表格
int reserve()
{
	int i = 0;
	while (strcmp(rwtab[i], _KEY_WORDEND))
	{
		if (!strcmp(rwtab[i], token))
			return i + 1;
		i++;
	}
	return 56;//如果不是关键字,则返回种别码10
}

//回退一个字符
void retract()
{
	p_input--;
}

//词法扫描程序
WORD* scanner()
{
	WORD* myword = new WORD;
	myword->typenum = 10;  //初始值
	myword->word = "";
	p_token = 0;   //单词缓冲区指针
	get_ch();
	removal_White();//去掉空白
	if (letter())//判断读取到的首字母是字母
	{
		//如int
		while (letter() || digit())
		{
			concat(); //连接
			get_ch();
		}
		retract(); //回退一个字符
		myword->typenum = reserve();//判断是否为关键字,返回种别码
		if (myword->typenum == 56) myword->word = "ident";
		else myword->word = token;
		return myword;
	}
	else if (digit())  //判断读取到的单词首字符是数字
	{
		while (digit()) //所有数字连接起来
		{
			concat();
			get_ch();
		}
		retract();
		//数字单词种别码统一为57
		myword->typenum = 57;
		myword->word = "inconst";
		return(myword);
	}
	else
	{
		switch (ch)
		{
		case '=':
			get_ch();
			if (ch == '=')
			{
				myword->typenum = 18;
				myword->word = "rop";
				return(myword);
				break;
			}
			retract();
			myword->typenum = 17;
			myword->word = "becomes";
			return(myword);
			break;
		case '+':
			myword->typenum = 15;
			myword->word = "plus";
			return(myword);
			break;
		case '*':
			myword->typenum = 16;
			myword->word = "times";
			return(myword);
			break;
		case '(':
			myword->typenum = 24;
			myword->word = "(";
			return(myword);
			break;
		case ')':
			myword->typenum = 25;
			myword->word = ")";
			return(myword);
			break;
		case ':':
			get_ch();
			if (ch == '=')
			{
				myword->typenum = 12;
				myword->word = "a";
				return(myword);
				break;
			}
			else
				break;
		case ';':
			myword->typenum = 13;
			myword->word = ";";
			return(myword);
			break;
		case '>':
			get_ch();
			if (ch == '=')
			{
				myword->typenum = 18;
				myword->word = "rop";
				return(myword);
				break;
			}
			retract();
			myword->typenum = 18;
			myword->word = "rop";
			return(myword);
			break;
		case '<':
			get_ch();
			if (ch == '=')
			{
				myword->typenum = 18;
				myword->word = "rop";
				return(myword);
				break;
			}
			else
			{
				retract();
				myword->typenum = 18;
				myword->word = "rop";
				return (myword);
			}
		case '!':
			get_ch();
			if (ch == '=')
			{
				myword->typenum = 18;
				myword->word = "rop";
				return(myword);
				break;
			}
			retract();
			myword->typenum = -1;
			myword->word = "ERROR";
			return(myword);
			break;
		case '#':
			myword->typenum = 14;
			myword->word = "jinghao";
			return (myword);
			break;
		default:
			myword->typenum = -1;
			myword->word = "ERROR";
			return(myword);
			break;
		}
	}
}

编译原理实验二之语法分析(算数表达式的扩充)-CSDN博客

  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冬天的枫树

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值