编译实验1--词法分析

本文档描述了一个实验,旨在通过编写C/C++程序实现对Pascal语言子集的词法分析。实验要求将源程序字符流转换为内码,并为标识符创建符号表。程序设计语言的描述采用扩展的BNF表示,内码单词对照表给出,实验代码展示了如何识别关键字、标识符、数字和特殊字符。
摘要由CSDN通过智能技术生成

实验一 词法分析程序

目的和内容

  1. 实验目的:通过完成词法分析程序,了解词法分析的过程。
  2. 实验内容:用C/C++实现对Pascal的子集程序设计语言的词法识别程序。
  3. 实验要求:将该语言的源程序,也就是相应字符流转换成内码,并根据需要是否对于标识符填写相应的符号表供编译程序的以后各阶段使用。

程序设计语言的描述

程序设计语言的描述采用扩充的BNF表示:
<程序>→<程序首部><分程序>.
<程序首部>→PROGRAM标识符;
<分程序>→[<常量说明部分>][<变量说明部分>][<过程说明部分>]<复合语句>
<常量说明部分>→CONST<常量定义>{,<常量定义>};
<常量定义>→标识符=无符号整数
<变量说明部分>→VAR<变量定义>(;<变量定义>);
<变量定义>→标识符{,标识符}:<类型>
<类型>→INTEGER|LONG
<过程说明部分>→<过程首部><分程序>;{<过程首部><分程序>;}
<过程首部>→PROCEDURE标识符;| PROCEDURE标识符(标识符:<类型>);
<语句>→<赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>
|<读语句>|<写语句>|<复合语句>|ε
<赋值语句>→标识符:=<表达式>
<条件语句>→IF<条件>THEN<语句>
<当型循环语句>→WHILE<条件>DO<语句>
<过程调用语句>→标识符 | 标识符(<表达式>)
<读语句>→READ(标识符,{标识符})
<写语句>→WRITE(<表达式>{,<表达式>})
<复合语句>→BEGIN<语句>{;<语句>}END
<条件>→<表达式><关系运算符><表达式> | ODD<表达式>
<表达式>→[+|-]<项>{<加型运算符><项>}
<项>→<因子>{<乘型运算符><因子>}
<因子>→标识符 | 无符号整数 | (<表达式>)
<加型运算符>→+|-
<乘型运算符>→* | /
<关系运算符>→=|<>|<|<=|>|>=
其中:
< >:用左右尖括号括起的字符串表示非终结符号
::= : 定义为
{ }:表示该语法成分可以0—n次重复。
[ ]:表示方括号内为可选项,即0或1次。

程序设计语言单词的内部编码

下表为词法分析中的内码单词对照表

内码

单词

内码

单词

内码

单词

内码

单词

1

PROGRAM

2

CONST

3

VAR

4

INTEGER

5

LONG

6

PROCEDURE

7

IF

8

THEN

9

WHILE

10

DO

11

READ

12

WRITE

13

BEGIN

14

END

15

ODD

16

+

17

-

18

*

19

/

20

=

21

<> 

22

23

<=

24

25

>=

26

,

27

.

28

;

29

:

30

:=

31

(

32

)

33

无符号整数

34

标识符

35

#

 

 

实验流程

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

实验代码

#include<bits/stdc++.h>
using namespace std;
#define lenth1 15
#define lenth2 17
struct Ident
{
	char name[21];
	int type;
	int addr;
};
Ident indent[1000];

struct St
{
	char name[21];
	int code;
};
St sym;

int lenth = 0;  // 表示标识符表长度
FILE *f1, * f2; //f1、f2分别指向输入输出文件

int line = 0, row = 0, val;

void getsym();
char getchr();
void error(int);

int main(int argc,char *argv[])
{
	char ft[12], * fc;

	if ((f1 = fopen(argv[1], "r"))== NULL) {  // 打开输入文件流
		cout << "can not open the input file!" << endl;
		exit(0);
	}

	if (argc <= 2) {  // 没有指定输出文件名
		strcpy(ft, argv[1]); //ft目标中间文件 =》*.tmp
		if ((fc = strchr(ft, '.')) != NULL) {
			strcpy(fc, ".temp");
		}
		else {
			strcat(ft, ".temp");
		}
	}
	else {
		strcpy(ft, argv[2]);
	}
	if ((f2 = fopen(ft, "w")) == NULL) { // 打开输出文件流
		cout << "can not open the output file" << endl;
		exit(0);
	}

	while (!feof(f1)) {
		getsym();
		printf("%s ==>%d\n", sym.name, sym.code); //控制台打印
		fprintf(f2, "%s ==>%d\n", sym.name, sym.code); //输出文件
	}
	fclose(f1);fclose(f2);
	return 0;
}

void getsym() {
	static char a[lenth1][10] = {
		"program","const","var","integer","long","procedure","if",
		"then","while","do","read","write","begin","end","odd"
	},
		d[lenth2][3] = { "+","-","*","/","=","<>","<","<=",">",">=",
						".",",",";",":",":=","(",")" },
		str[21], ch = ' ';
	int i, n; // n判断单词长度,i判断是哪个关键字
	while (isspace(ch))
	{
		ch = getchr();
	}
	if (isalpha(ch)) { //判断字母开头的字符
		n = 0;
		while (isalpha(ch) || isdigit(ch)) {
			if (isalpha(ch))
				ch = tolower(ch);
			str[n++] = ch;
			ch = getchr();
		}
		str[n] = '\0';
		for (i = 0;i < lenth1;i++) {
			if (!strcmp(str, a[i]))
				break;
		}
		if (i < lenth1) { //找到匹配关键字
			strcpy(sym.name, a[i]);
			sym.code = i + 1;
		}
		else {
			for (i = 0;i < lenth;i++) { //遍历已记录的标识符记录表
				if (!strcmp(str, indent[i].name))
					break;
			}
			if (i == lenth) {
				strcpy(indent[i].name, str);
			}
			strcpy(sym.name, indent[i].name);
			sym.code = 34;
		}
	}
	else if (isdigit(ch)) { // 判断数字开头的字符
		val = 0;n = 0;
		while (isdigit(ch)) {
			val = val * 10 + ch - '0';
			sym.name[n++] = ch;
			ch = getchr();
		}
		sym.name[n] = '\0';
		sym.code = 33;
	}
	else {  // 判断特殊字符
		if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '=' ||
			ch == '.' || ch == ',' || ch == ';' || ch == '(' || ch == ')') {
			str[0] = ch; str[1] = '\0';
			ch = getchr();
			for (i = 0;i < lenth2;i++) {
				if (!strcmp(str, d[i])) {
					strcpy(sym.name, str);
					sym.code = i + 16;
					break;
				}
			}
		}
		else if (ch == '#') {
			str[0] = ch; str[1] = '\0';
			ch = getchr();
			strcpy(sym.name, str);
			sym.code = 35;
		}
		else if (ch == '<') {
			char b = getchr();
			if (b == '>') {
				str[0] = '<';str[1] = '>';str[2] = '\0';
				strcpy(sym.name, str);
				sym.code = 21;
				ch = getchr();
			}
			else if (b == '=') {
				str[0] = '<';str[1] = '=';str[2] = '\0';
				strcpy(sym.name, str);
				sym.code = 23;
				ch = getchr();
			}
			else {
				str[0] = '<';str[1] = '\0';
				strcpy(sym.name, str);
				sym.code = 22;
				ch = b;
			}
		}
		else if (ch == '>') {
			char b = getchr();
			if (b == '=') {
				str[0] = '>';str[1] = '=';str[2] = '\0';
				strcpy(sym.name, str);
				sym.code = 25;
				ch = getchr();
			}
			else {
				str[0] = '>';str[1] = '\0';
				strcpy(sym.name, str);
				sym.code = 24;
				ch = b;
			}
		}
		else if (ch == ':') {
			char b = getchr();
			if (b == '=') {
				str[0] = ch;str[1] = b;str[2] = '\0';
				strcpy(sym.name, str);
				sym.code = 30;
				ch = getchr();
			}
			else {
				str[0] = ch;str[1] = '\0';
				strcpy(sym.name, str);
				sym.code = 29;
				ch = b;
			}
		}
	}
}


char getchr() {  // 从文件中获取下一个非空字符
	char ch = fgetc(f1);
	if (ch == '\n') {
		row = 1;
		line++;
	}
	else {
		if (ch != ' ' && ch != '\t') {
			row++;
		}
	}
	return ch;
}

void error(int n) {
	printf("There are %d-error\n", n);
	exit(0);
}


在这里插入图片描述

在这里插入图片描述

完成对某一种常用高级语言(如Pascal、C语言、PL/0语言)的各类单词进行词法分析。 PL/0语言文法的EBNF描述: 〈程序〉∷= 〈分程序〉。 〈分程序〉∷= [〈常量说明部分〉][〈变量说明部分〉][〈过程说明部分〉]〈语句〉 〈常量说明部分〉∷= CONST〈常量定义〉{。〈常量定义〉}; 〈常量定义〉∷= 〈标志符〉=〈无符号整数〉 〈无符号整数〉∷= 〈数字〉{〈数字〉} 〈变量说明部分〉∷= VAR〈标志符〉{,〈标志符〉}; 〈标志符〉∷= 〈字母〉{〈字母〉|〈数字〉} 〈过程说明部分〉∷= 〈过程首部〉〈分程序〉{;〈过程说明部分〉}; 〈过程首部〉∷= PROCEDURE〈标志符〉; 〈语句〉∷= 〈赋值语句〉|〈条件语句〉|〈当型循环语句〉|〈过程调用语句〉|〈读语句〉|〈写语句〉|〈复合语句〉|〈空〉 〈赋值语句〉∷= 〈标志符〉:=〈表达式〉 〈复合语句〉∷= BEGIN〈语句〉{;〈语句〉}END 〈条件〉∷= 〈表达式〉〈关系运算符〉〈表达式〉|ODD〈表达式〉 〈表达式〉∷= [+|-]〈项〉{〈加法运算符〉〈项〉} 〈项〉∷= 〈因子〉{〈乘法运算符〉〈因子〉} 〈因子〉∷= 〈标志符〉|〈无符号整数〉|‘(’〈表达式〉‘)’ 〈加法运算符〉∷= +|- 〈乘法运算符〉∷= *|/ 〈关系运算符〉∷= =|#|<|>|<=|>= 〈条件语句〉∷= IF〈条件〉THEN〈语句〉 〈过程调用语句〉∷= CALL〈标志符〉 〈当型循环语句〉∷= WHILE〈条件〉DO〈语句〉 〈读语句〉∷= READ‘(’〈标志符〉{,〈标志符〉}‘)’ 〈写语句〉∷= WRITE‘(’〈表达式〉{,〈表达式〉}‘)’ 〈字母〉∷= a|b|…..|X|Y|Z 〈数字〉∷= 0|1|2|…..|8|9
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Andy-wen

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

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

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

打赏作者

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

抵扣说明:

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

余额充值