1.1 TEST 语言概述
TEST 语言的程序结构简单,整个程序相当于 C 语言的函数体,即由一对花
括号括起的语句序列,没有函数,没有数组;声明语句、表达式语句以及控制
语句和 C 语言类似。数据类型只有整型,一个声明语句只能声明一个变量;表
达式只有算术表达式和布尔表达式两种形式,其中算术表达式为整型变量和整
型常数的四则运算组合,布尔表达式为两个算术表达式的比较运算;控制语句
只有 if、while 和 for 三种语句;支持复合语句;read 语句和 write 语句实现
输入输出;注释仅为多行注释/* …… /。 1.2 TEST 语言的词法规则
1、标识符:字母打头,后接任意字母或数字。其中保留字为标识符的子集,包
括:if, else, for, while, int, write, read。
3、无符号整数:由数字组成,但最高位不能为 0,允许一位的 0。
4、分界符:(、)、;、{、}
5、运算符:+、-、、/、=、<、>、>=、<=、!=、==
6、注释符:/* */
1.3 TEST 语言的语法规则
- → {<declaration_list><statement_list>} 2) <declaration_list> → <declaration_list><declaration_stat> | ε 3) <declaration_stat> → int ID;
- <statement_list> → <statement_list>| ε 5) → <if_stat>|<while_stat>|<for_stat>|<read_stat> |<write_stat>|<compound_stat> |<assignment_stat>|; 6) <if_stat> → if (<bool_expression >) | if (<bool_expression>) else < statement > 7) <while_stat> → while (<bool_expression>) < statement > 8) <for_stat> → for (<assignment_expression>; <bool_expression>; <assignment_ expression >) 9) <write_stat> → write < arithmetic_expression >; 10) <read_stat> → read ID; 11) <compound_stat> → {<statement_list>} 12) <assignment_expression> → ID=<arithmetic_expression> 13) <assignment_stat> →<assignment_expression>; 14) <bool_expression>→<arithmetic_expression> > <arithmetic_expression> |<arithmetic_expression> < <arithmetic_expression> |<arithmetic_expression> >= <arithmetic_expression> |<arithmetic_expression> <= <arithmetic_expression> |<arithmetic_expression> == <arithmetic_expression> |<arithmetic_expression> != <arithmetic_expression> 15) <arithmetic_expression> → <arithmetic_expression>+ |< arithmetic_expression>- |< term > 16) < term > → < term >*|< term >/|< factor > 17) < factor > → (<arithmetic_expression>)|ID|NUM
2 目标机器
3.1.4 实验内容
1、根据 TEST 语言的词法规则,分别写出每条词法规则对应的正则表达式; 2、将每一个正则表达式转换为 NFA; 3、将多个 NFA 合并后进行确定化并化简; 4、参阅在实验语言部分给出的 TEST 语言语法规则,确定单词分类、单词输出方
案; 5、根据最小的 DFA 编写词法分析程序; 6、对下面的 TEST 语言源程序进行词法分析,将合法单词存入 lex.txt,并报告 词法错误及其位置。注:不能修改以下源程序。
{
/*This a test program.*/
int abc;
int 123;
int A$@;
int 2a;
int a2;
read n;
n = 012345;
for (i=1;i<=n; i= i+1)
{
abc=abc+i;
}
if(i!=n) n = n+i;
if (!n) b = b+c;
/*The loop ended
write abc;
}
3.1.5 实验报告要求
1、实验设计
(1)DFA 设计过程:给出每条词法规则对应的正则表达式、由正则表达式构
造的 NFA、合并后的 NFA、确定化后的 DFA、最小化后的 DFA。
(2)词法分析结果的输出形式:给出单词类别。
2、实验过程 (1)简述完成实验的步骤。 (2)实验调试记录:实验过程中遇到的问题,对该问题进行描述,分析其产 生的原因,提出解决方案,给出最后的解决结果。 3、实验结果
(1)给出词法分析程序识别的单词。
(2)给出词法分析程序识别出的词法错误。
4、讨论与分析
(1)通过实验对词法分析相关知识点的理解。
(2)回答实验思考部分提出的问题。
3.1.6 实验思考
1、设计的词法分析程序是否满足最长匹配原则?如果满足请给出实现方案。如
果不满足请给出改进方案。
2、给出单词分类方案,并说明理由。
3、简述构建词法分析程序一般步骤。
词法分析程序:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<stdio.h>
#include<ctype.h>
using namespace std;
#define keywordSum 8
char *keyword[keywordSum] = {
"if", "else", "for", "while", "do", "int", "read", "write" };
//单分界符
char singleword[50] = "+-*{}();,:";
//双分界符
char doubleword[10] = "<>=!";
char Scanin[300] = "test.txt";
char Scanout[300] = "testout.txt";
int line = 1;
FILE *fin, *fout;
int TESTscan()
{
char ch, token[40]; //ch读入字符 token保存识别单词
int es = 0, j, n;
if ((fin = fopen(Scanin, "r")) == NULL)
{
cout << "输入文件有误";
return 1;
}
if ((fout = fopen(Scanout, "w")) == NULL)
{
cout << "输出文件有误";
return 2;
}
ch = getc(fin);
while (ch != EOF)
{
while (ch == ' ' || ch == '\n' || ch == '\t')
{
if (ch == '\n'){
line++;
}
ch = getc(fin);
}
if (isalpha(ch))
{
token[0] = ch;
j = 1;
ch = getc(fin);
while (isalnum(ch))
{
token[j++] = ch;
ch = getc(fin);
}
token[j] = '\0';
n = 0;
while ((n < keywordSum) && strcmp(token, keyword[n]))n++;
if (n >= keywordSum)
{
fprintf(fout, "%s\t%s\n", "ID", token);
}
else
{
fprintf(fout, "%s\t%s\n", token, token);
}
}
else if (isdigit(ch))
{
token[0] = ch;
j = 1;
ch = getc(fin);
while (isdigit(ch))
{
token[j++] = ch;
ch = getc(fin);
}
token[j] = '\0';
fprintf(fout, "%s\t%s\n", "NUM", token);
}
else if (strchr(singleword, ch)>0)
{
token[0] = ch;
token[1] = '\0';
ch = getc(fin);
fprintf(fout, "%s\t%s\n", token, token);
}
else if (strchr(doubleword, ch)>0)
{
token[0] = ch;
ch = getc(fin);
if (ch == '=')
{
token[1] = ch;
token[2] = '\0';
ch = getc(fin);
}
else
{
token[1] = '\0';
}
fprintf(fout, "%s\t%s\n", token, token);
}
else if (ch == '/')
{
ch = getc(fin);
if (ch == '*')
{
char ch1;
ch1 = getc(fin);
do
{
ch = ch1;
ch1 = getc(fin);
} while ((ch != '*' || ch1 != '/') && ch1 != EOF);
ch = getc(fin);
}
else
{
token[0] = '/';
token[1] = '\0';
fprintf(fout, "%s\t%s\n", token, token);
}
}
else
{
token[0] = ch;
token[1] = '\0';
ch = getc(fin);
es = 3;
printf("ERROR AT LINE%d: %s\n",line, &token);
}
}
fclose(fin);
fclose(fout);
return(es);
}
int main()
{
int es = 0;
es = TESTscan();
if (es > 0)cout << "词法分析有错,编译停止!\n";
else cout << "词法分析成功!\n";
system("pause");
return 0;
}
结果:
{
{
int int
ID abc
; ;
int int
NUM 123
; ;
int int
ID A
; ;
int int
NUM 2
ID a
; ;
int int
ID a2
; ;
read read
ID n
; ;
ID n
= =
NUM 012345
; ;
for for
( (
ID i
= =
NUM 1
; ;
ID i
<= <=
ID n
; ;
ID i
= =
ID i
+ +
NUM 1
) )
{
{
ID abc
= =
ID abc
+ +
ID i
; ;
} }
if if
( (
ID i
!= !=
ID n
) )
ID n
= =
ID n
+ +
ID i
; ;
if if
( (
! !
ID n
) )
ID b
= =
ID b
+ +
ID c
; ;