实验一 词法分析程序
目的和内容
- 实验目的:通过完成词法分析程序,了解词法分析的过程。
- 实验内容:用C/C++实现对Pascal的子集程序设计语言的词法识别程序。
- 实验要求:将该语言的源程序,也就是相应字符流转换成内码,并根据需要是否对于标识符填写相应的符号表供编译程序的以后各阶段使用。
程序设计语言的描述
程序设计语言的描述采用扩充的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);
}