《编译原理》实验一:词法分析
该分类为本人在本学期《编译原理》课程上的实验报告,实验对象语言为教学用PL/0语言,实验所用语言为C++。
全部报告仅供参考,如有缺漏或错误,烦请指出,Thanks ♪(・ω・)ノ
一. 设计思想
根据 PL/0 语言的文法规范,编写 PL/0 语言的词法分析程序。
1.单词种类及其正规式
(1)基本字
单词的值 | 单词类型 | 正规式 r |
begin | beginsym | begin |
call | callsym | call |
const | constsym | const |
do | dosym | do |
end | endsym | end |
if | ifsym | if |
odd | oddsym | odd |
procedure | proceduresym | procedure |
read | readsym | read |
then | thensym | then |
var | varsym | var |
while | whilesym | while |
write | writesym | write |
(2)标识符
单词的值 | 单词类型 | 正规式 r |
标识符 | Ident | (字母)(字母|数字)* |
(3)常数
单词的值 | 单词类型 | 正规式 r |
常数 | number | (数字)(数字)* |
(4)运算符
单词的值 | 单词类型 | 正规式 r |
+ | plus | + |
- | minus | - |
* | times | * |
/ | slash | / |
= | eql | = |
<> | neq | <> |
< | lss | < |
<= | leq | <= |
> | gtr | > |
>= | geq | >= |
:= | becomes | := |
(5)界符
单词的值 | 单词类型 | 正规式 r |
( | lparen | ( |
) | rparen | ) |
, | comma | , |
; | semicolon | ; |
. | period | . |
2.NFA
3.DFA
4.最小化 DFA
二. 算法流程
三. 源程序
1 #include <iostream>
2 #include <string>
3 #include <vector>
4 using namespace std;
5
6 void getChar(const string s,int& idx,char& ch) // 取下个字符
7 {
8 ch=s[idx++];
9 return;
10 }
11
12 void getBC(const string s,int& idx,char& ch) // 跳过空格
13 {
14 while (ch==' ')
15 {
16 getChar(s,idx,ch);
17 }
18 return;
19 }
20
21 void concat(string& strToken,const char ch) // 字符拼接
22 {
23 strToken+=ch;
24 return;
25 }
26
27 void retract(int& idx,char& ch) // 退一格
28 {
29 --idx;
30 ch=' ';
31 return;
32 }
33 // 基本字数组
34 string basicWord[13]={"begin","call","const","do","end",
35 "if","odd","procedure","read",
36 "then","var","while","write"};
37 // 处理基本字
38 string basic(const string strToken)
39 {
40 bool isbasic=false;
41 for (int i=0;i<13;++i)
42 {
43 if (strToken==basicWord[i])
44 {
45 isbasic=true;
46 break;
47 }
48 }
49 if (isbasic) // 如果是基本字
50 {
51 return strToken;
52 }
53 else // 否则是标识符
54 {
55 return "ident";
56 }
57 }
58
59
60 int main()
61 {
62 vector<string> v;
63 string s="";
64 string str;
65 while (cin>>str) // 循环读入
66 {
67 s=s+' '+str;
68 }
69
70 int idx=0;
71 while (idx<(int)s.length()){ // 处理每个字符
72 char ch=' ';
73 string strToken="";
74 getChar(s,idx,ch);
75 getBC(s,idx,ch);
76 if (isalpha(ch)) // 如果是字母
77 {
78 while (isalnum(ch)) // 读字母或数字
79 {
80 concat(strToken,ch);
81 getChar(s,idx,ch);
82 }
83 retract(idx,ch);
84 string ret=basic(strToken);
85 if (ret=="ident")
86 {
87 v.push_back(string("(ident,"+strToken+')'));
88 }
89 else
90 {
91 v.push_back(string('('+ret+"sym"+','+strToken+')'));
92 }
93 }
94 else if (isdigit(ch)) // 如果是数字
95 {
96 while (isdigit(ch)) // 持续获取数字
97 {
98 concat(strToken,ch); // 将所有数字拼起来
99 getChar(s,idx,ch); // 下一个字符
100 }
101 retract(idx,ch);
102 v.push_back(string(+"(number,"+strToken+')'));
103 }
104 else if (ch=='+')
105 {
106 v.push_back("(plus,+)");
107 }
108 else if (ch=='-')
109 {
110 v.push_back("(minus,-)");
111 }
112 else if (ch=='*')
113 {
114 v.push_back("(times,*)");
115 }
116 else if (ch=='/')
117 {
118 v.push_back("(slash,/)");
119 }
120 else if (ch=='=')
121 {
122 v.push_back("(eql,=)");
123 }
124 else if (ch=='<') // '<'后有 <>、<= 两种可能
125 {
126 getChar(s,idx,ch);
127 if (ch=='>')
128 {
129 v.push_back("(neq,<>)");
130 }
131 else if (ch=='=')
132 {
133 v.push_back("(leq,<=)");
134 }
135 else
136 {
137 retract(idx,ch);
138 v.push_back("(les,<)");
139 }
140 }
141 else if (ch=='>') // '>'后有 >= 的可能
142 {
143 getChar(s,idx,ch);
144 if (ch=='=')
145 {
146 v.push_back("(geq,>=)");
147 }
148 else
149 {
150 retract(idx,ch);
151 v.push_back("(gtr,>)");
152 }
153 }
154 else if (ch==':')
155 {
156 getChar(s,idx,ch);
157 if (ch=='=')
158 {
159 v.push_back("(becomes,:=)");
160 }
161 }
162 else if (ch=='(')
163 {
164 v.push_back("(lparen,()");
165 }
166 else if (ch==')')
167 {
168 v.push_back("(rparen,))");
169 }
170 else if (ch==',')
171 {
172 v.push_back("(comma,,)");
173 }
174 else if (ch==';')
175 {
176 v.push_back("(semicolon,;)");
177 }
178 else if (ch=='.')
179 {
180 v.push_back("(period,.)");
181 }
182 else
183 {
184 v.push_back("(OTHER,"+ch+')');
185 }
186 }
187 for (int i=0;i<(int)v.size();++i) // 输出
188 {
189 cout<<v[i]<<endl;
190 }
191 return 0;
192 }
四. 调试数据
1.样例输入:
1 const a=10;
2 var b,c;
3 begin
4 read(b);
5 c:=a+b;
6 write(c)
7 end.
样例输出:
(constsym,const)
(ident,a)
(eql,=)
(number,10)
(semicolon,;)
(varsym,var)
(ident,b)
(comma,,)
(ident,c)
(semicolon,;)
(beginsym,begin)
(readsym,read)
(lparen,()
(ident,b)
(rparen,))
(semicolon,;)
(ident,c)
(becomes,:=)
(ident,a)
(plus,+)
(ident,b)
(semicolon,;)
(writesym,write)
(lparen,()
(ident,c)
(rparen,))
(endsym,end)
(period,.)
图片展示:
2. 样例输入:
1 const a=10;
2 var b,c,d;
3 begin
4 read(b);
5 read(c);
6 d:=a+b+c;
7 write(d)
8 end.
样例输出:
1 (constsym,const)
2 (ident,a)
3 (eql,=)
4 (number,10)
5 (semicolon,;)
6 (varsym,var)
7 (ident,b)
8 (comma,,)
9 (ident,c)
10 (comma,,)
11 (ident,d)
12 (semicolon,;)
13 (beginsym,begin)
14 (readsym,read)
15 (lparen,()
16 (ident,b)
17 (rparen,))
18 (semicolon,;)
19 (readsym,read)
20 (lparen,()
21 (ident,c)
22 (rparen,))
23 (semicolon,;)
24 (ident,d)
25 (becomes,:=)
26 (ident,a)
27 (plus,+)
28 (ident,b)
29 (plus,+)
30 (ident,c)
31 (semicolon,;)
32 (writesym,write)
33 (lparen,()
34 (ident,d)
35 (rparen,))
36 (endsym,end)
37 (period,.)
图片展示:
3.样例输入:
1 const a=10;
2 const b=10;
3 var c;
4 begin
5 c:=a+b;
6 write(c)
7 end.
样例输出:
1 (constsym,const)
2 (ident,a)
3 (eql,=)
4 (number,10)
5 (semicolon,;)
6 (constsym,const)
7 (ident,b)
8 (eql,=)
9 (number,10)
10 (semicolon,;)
11 (varsym,var)
12 (ident,c)
13 (semicolon,;)
14 (beginsym,begin)
15 (ident,c)
16 (becomes,:=)
17 (ident,a)
18 (plus,+)
19 (ident,b)
20 (semicolon,;)
21 (writesym,write)
22 (lparen,()
23 (ident,c)
24 (rparen,))
25 (endsym,end)
26 (period,.)
图片展示:
五. 实验调试情况及体会
略
参考博客: