词法分析小程序。
实验目的
1.待分析的简单的词法
(1)关键字:
begin if then while do end
注:所有的关键字都是小写。
(2)运算符和界符
. + - * / =<> < <= > >= ( ) ; :=
(3)其他单词是标识符(IDENT)和整型常数(NUMBER),通过以下正规式定义:
IDENT ::= letter (letter |digit)*
NUMBER ::= digit digit*
注:所有的IDENT和NUMBER的长度不超过20
(4)空格有空白、制表符和换行符组成。空格一般用来分隔IDENT、NUMBER、运算符、界符和关键字,词法分析阶段通常被忽略。整个程序串长度不超过80个字符。
2. 各种单词符号对应的类别值:
表 各种单词符号对应的类别码
|
单词符号 |
是否保留字 |
枚举值 |
类别码 |
|
|
period |
0 | |
|
+ |
|
plus |
1 |
|
- |
|
minus |
2 |
|
* |
|
times |
3 |
|
/ |
|
slash |
4 |
|
= |
|
eql |
5 |
|
<> |
|
neq |
6 |
|
< |
|
lss |
7 |
|
<= |
|
leq |
8 |
|
> |
|
gtr |
9 |
|
>= |
|
geq |
10 |
|
( |
|
lparen |
11 |
|
) |
|
rparen |
12 |
|
; |
|
semicolon |
13 |
|
:= |
|
becomes |
14 |
|
begin |
Y |
beginsym |
15 |
|
end |
Y |
endsym |
16 |
|
if |
Y |
ifsym |
17 |
|
then |
Y |
thensym |
18 |
|
while |
Y |
whilesym |
19 |
|
do |
Y |
dosym |
20 |
|
|
21 | ||
|
NUMBER |
|
number |
22 |
3. 词法分析程序的功能:
输入:所给文法的源程序字符串,以“.”结束。
输出:二元组(sym, token或number)构成的序列。
其中:sym为单词种别
token为存放的单词自身字符串;
number为整型常数。对于数值串需要转化为实际的值。
示例:
源程序:begin x:=9;if x<10 then x:=(x+10)*2 end.
经过词法分析后输出如下序列:(15,begin)(21,x)(14,:=)(22,9)(13,;)……
4. 词法分析程序的设计
1)词法分析识原理采用状态转换图方法:
设计思路
1.实验的设计方法:遍历字符串,模拟判断。
2.设计流程描述:
字符对应表
增加保留字表:
判断过程:
3.主要技术难点:
1)结束标记:这里选择使用‘.’作为结束标记
2)设计我们要判断的字符对应表
3)建立字符和字符对应表之间的映射
代码:
#include <bits/stdc++.h>
using namespace std;
/*
变量说明:
line 从终端读入的字符串; 当前所指位置在计数器 p, 字符为ch
token 正在识别的单词字符串; 当前所指位置在计数器 m
num 整型常数
sym 每个单词符号种类
word 保留字表
*/
enum symbol {
period=0,
Plus=1,
Minus=2,
times=3,
slash=4,
eql=5,
neq=6,
lss=7,
leq=8,
gtr=9,
geq=10,
lparen=11,
rparen=12,
semicolon=13,
becomes=14,
beginsym=15,
endsym=16,
ifsym=17,
thensym=18,
whilesym=19,
dosym=20,
ident=21,
number=22,
note=23,
nil,
};
char line[80],token[8],ch;
int p,m, num;
enum symbol sym;
char* word[6]={"begin","if","then","while","do","end"};
void getsym();
void printsym(enum symbol sym);
int main()
{
freopen("t.txt","r",stdin);
//读了字符串, 直到遇.结束
p=0;
printf("\n please input a string(end with '.'): \n");
do
{
scanf("%c",&ch);
line[p++]=ch;
}while(ch!='.');
line[p++]='\0';
//逐个单词扫描;
p=0;
do
{
getsym(); //当前扫描的单词存放在syn中
printsym(sym);
} while (sym != period);
getchar();
return 0;
}
void getsym()
{
for(m=0; m<8;m++) token[m++]=NULL;
ch=line[p++];
m=0;
/************************************************
**** ****
**** TODO: 单词识别 ****
**** ****
*************************************************/
while((ch==' '||ch=='\n')) ch=line[p++];
//字母打头的字符串;标识符
if((ch<='z'&&ch>='a')||(ch<='Z'&&ch>='A'))
{
do
{
token[m++]=ch;
ch=line[p++];
}while((ch<='z'&&ch>='a')||(ch<='Z'&&ch>='A')||(ch<='9'&&ch>='0'));
sym=ident;
token[m++]='\0';
ch=line[p--];
for(int n=0;n<6;n++)
{
if(strcmp(token,word[n])==0)
{
if(n==0) sym=beginsym;
else if(n==1) sym=endsym;
else if(n==2) sym=ifsym;
else if(n==3) sym=thensym;
else if(n==4) sym=whilesym;
else if(n==5) sym=dosym;
break;
}
}
/*TODO识别标识符IDENT和保留字*/
}
else if((ch<='9'&&ch>='0'))
{
num=0;
do{
num=num*10+ch-'0';
ch=line[p++];
}while((ch<='9'&&ch>='0'));
ch=line[p--];
sym=number;
/*TODO识别数字NUMBER*/
}
else {
switch(ch)
{
case ':': //赋值符号
token[m++]=ch;
ch=line[p++];
if(ch=='=')
{
sym=becomes;
token[m++]=ch;
}
else{
sym=nil;
}
break;
case '<': //<=和<符号
token[m++]=ch;
ch=line[p++];
if(ch=='=')
{
token[m++]=ch;
sym=leq;
}
else if(ch=='>'){
token[m++]=ch;
sym=neq;
}
else{
sym=lss;
p--;
}
break;
case '>': //>=和>符号
token[m++]=ch;
ch=line[p++];
if(ch=='=')
{
sym=geq;
token[m++]=ch;
}
else{
sym=gtr;
p--;
}
break;
case '+':
sym=Plus;
token[m++]=ch;
break;
case '-':
sym=Minus;
token[m++]=ch;
break;
case '*':
sym=times;
token[m++]=ch;
break;
case '/':
ch=line[p++];
if(ch=='*'){
//cout<<"in\n";
char fr;//前面的一个符号
fr='*';
ch=line[p++];
while(1){
fr=ch;
ch=line[p++];
if(fr=='*'&&ch=='/') break;
}
sym=note;
token[m++]=ch;
}
else
{
sym=slash;
token[m++]=ch;
p--;
}
break;
case '=':
sym=eql;
token[m++]==ch;
break;
case '(':
sym=lparen;
token[m++]=ch;
break;
case ')':
sym=rparen;
token[m++]=ch;
break;
case ';':
sym=semicolon;
token[m++]=ch;
break;
case '.':
sym=period;
token[m++]=ch;
break;
case ' ':
token[m++]=ch;
break;
default:
sym=nil;
break;
}
}
token[m++]='\0';
}
void printsym(enum symbol sym)
{
/************************************************
**** ****
**** TODO: 输出单词 ****
**** ****
*************************************************/
switch(sym)
{
case period:
return;
case number:
printf("( number,%-10d)\n",num);
break;
case nil:
printf("you have input a wrong string\n");
break;
case note:
printf("this is notes\n");
break;
case Plus:
printf("( Plus,%-10s)\n","+");
break;
case Minus:
printf("( Minus,%-10s)\n","-");
break;
case times:
printf("( times,%-10s)\n","*");
break;
case slash:
printf("( slash,%-10s)\n","/");
break;
case eql:
printf("( eql,%-10s)\n","=");
break;
case neq:
printf("( neq,%-10s)\n","><");
break;
case lss:
printf("( lss,%-10s)\n","<");
break;
case leq:
printf("( leq,%-10s)\n","<=");
break;
case gtr:
printf("( gtr,%-10s)\n",">");
break;
case geq:
printf("( geq,%-10s)\n",">=");
break;
case lparen:
printf("( lparen,%-10s)\n","(");
break;
case rparen:
printf("( rparen,%-10s)\n",")");
break;
case semicolon:
printf("( semicolon,%-10s)\n",";");
break;
case becomes:
printf("( becomes,%-10s)\n",":=");
break;
case beginsym:
printf("( beginsym,%-10s)\n","begin");
break;
case endsym:
printf("( endsym,%-10s)\n","end");
break;
case ifsym:
printf("( ifsym,%-10s)\n","if");
break;
case thensym:
printf("( thensym,%-10s)\n","then");
break;
case whilesym:
printf("( whilesym,%-10s)\n","while");
break;
case dosym:
printf("( dosym,%-10s)\n","do");
break;
case ident:
printf("( ident,%-10s)\n",token);
break;
default:
break;
}
}
结果截屏:
这篇博客介绍了词法分析的基本概念,包括关键字、运算符、标识符和整型常数的定义,并展示了词法分析程序的功能。该程序接收源程序字符串,输出单词类别和对应的字符串或数值。文章提到了状态转换图方法,并讨论了设计过程和技术难点,如结束标记的选择和字符映射的建立。
2822

被折叠的 条评论
为什么被折叠?



