PL/0语言词法分析器

时间:2022-05-13 16:54:38

前言:关于词法分析的基础知识的介绍可以看一下这篇博客,我再累述估计也不会有这篇讲的清楚QAQ。 https://www.cnblogs.com/yanlingyin/archive/2012/04/17/2451717.html    默认大家已经对词法分析有了基本的了解了。

一:下面讨论PL/0语言的词法分析器的单词结构

1、关键字     

  关键字(11):空格分隔列表如下

  begin  end  if  then  while  do  const  var  call  procedure  odd

2、运算符和界符  

  算符和界符(14个):空格分隔列表如下

  +  -  *  /  =  #  <  >  :=  (  )  ,  .  ;

 

3、标示符

        PL/0语言中标示符的定义为:开头可以是下划线或字母,后面可以是下划线、字母或数字。

4、常数

  整形数和浮点数

5、空白符

  PL/0语言中的空白符有:空格符、制表符、换行符,这些空白符在词法分析阶段可以被忽略。

6、注释

         PL/0语言中的注释形式为//,可以多行注释(*…*)。

二:PL/0的语言的词法分析器将要完成以下工作

 

(1) 跳过分隔符(如空格,回车,制表符);

 

(2) 识别诸如beginendifwhile等关键字;

 

(3) 识别非关键字的一般标识符。

 

(4) 识别常数数字序列。

 

(5) 识别前面列出的单字符操作符和:=双字符特殊符号。

 

(6)词法分析器的输出形式(种别,属性值)其中:种别在2、单词的种别”中进行了定义;

 

              属性值:若单词种别只代表唯一单词,属性值为空;

 

              若单词种别是标识符,为该单词在标识符表中的位置;

 

              若单词种别是常数,属性值为对应常数值。

三:代码实现

测试程序如下(我放置的路径为D:/b.txt,根据自己情况自行修改)

PL/0语言词法分析器PL/0语言词法分析器
 1 // PL/0 语法示例程序 
 2 
 3 (*
 4     计算1~10的阶乘
 5     多行注释    
 6 *)
 7 
 8 var n, f;
 9 begin
10      n := 0;
11      f := 1;
12      while n # 10 do
13      begin
14           n := n + 1;
15           f := f * n;
16      end;
17      call print;// 用于输出结果,假设预先声明
18 end.
View Code

种别码如下(我放置的路径为D:/a.txt,根据自己情况自行修改)

PL/0语言词法分析器PL/0语言词法分析器
 1 begin  1
 2 end  2
 3 if  3
 4 then 4
 5 while  5
 6 do  6
 7 const  7
 8 var  8
 9 call  9
10 procedure  10
11 odd  11
12 +  12
13 -  13
14 *  14
15 /  15
16 =  16
17 #  17
18 <  18
19 >  19
20 :=  20
21 (  21
22 )  22
23 ,  23
24 .  24
25 ;  25
26 (*多行注释*)    26
27 //单行注释  27
28 常数    28
29 标识符    29
View Code

实现代码如下

PL/0语言词法分析器PL/0语言词法分析器
  1 // pL/0语言词法分析器
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 struct _2tup
  5 {
  6     string token;
  7     int id;
  8 };
  9 bool is_blank(char ch)
 10 {
 11     return ch == ' ' || ch == '    ';//空格或控制字符
 12 }
 13 bool gofor(char& ch, string::size_type& pos, const string& prog)//返回指定位置的字符
 14 {
 15     ++pos;
 16     if (pos >= prog.size())
 17     {
 18         return false;
 19     }
 20     else
 21     {
 22         ch = prog[pos];
 23         return true;
 24     }
 25 }
 26 
 27 _2tup scanner(const string& prog, string::size_type& pos, const map<string, int>& keys, int& row)
 28 {
 29     /*
 30     if
 31         标示符
 32     else if
 33         数字
 34     else
 35         符号
 36     */
 37     _2tup ret;
 38     string token;
 39     int id = 0;
 40 
 41     char ch;
 42     ch = prog[pos];
 43 
 44     while(is_blank(ch))
 45     {
 46         ++pos;
 47         ch = prog[pos];
 48     }
 49     // 判断标示符、关键字
 50     if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_')
 51     {
 52         //保证读取一个单词
 53         while((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_')
 54         {
 55             token += ch;//追加标示符、关键字
 56             if (!gofor(ch, pos, prog))
 57             {
 58                 break;
 59             }
 60         }
 61         // 这里先看做都是其他标示符
 62         id = keys.size();
 63 
 64         // 验证是否是关键字
 65         map<string, int>::const_iterator cit = keys.find(token);//根据string类型的token返回int类型的id赋值给cit
 66         if (cit != keys.end())
 67         {
 68             id = cit->second;//此时是关键字,记录他的id
 69         }
 70     }
 71     // 识别常数
 72     else if ((ch >= '0' && ch <= '9') || ch == '.')
 73     {
 74         while (ch >= '0' && ch <= '9' || ch == '.')
 75         {
 76             token += ch;
 77             if (!gofor(ch, pos, prog))
 78             {
 79                 break;
 80             }
 81         }
 82         id = keys.size() - 1;
 83         int dot_num = 0;
 84         for (string::size_type i = 0; i != token.size(); ++i)
 85         {
 86             if (token[i] == '.')
 87             {
 88                 ++dot_num;
 89             }
 90         }
 91         if (dot_num > 1)
 92         {
 93             id = -1;
 94         }
 95     }
 96     else
 97     {
 98         map<string, int>::const_iterator cit;
 99         switch (ch)
100         {
101         case '-': // - 操作符
102             token += ch;
103             if (gofor(ch, pos, prog))
104             {
105                 if (ch == '-' || ch == '=' || ch == '>') // -- 操作符
106                 {
107                     token += ch;
108                     gofor(ch, pos, prog);
109                 }
110             }
111             cit = keys.find(token);
112             if (cit != keys.end())
113             {
114                 id = cit->second;
115             }
116             break;
117         case ':':
118              token += ch;
119             if (gofor(ch, pos, prog))
120             {
121                 if (ch == '=') // -- 操作符
122                 {
123                     token += ch;
124                     gofor(ch, pos, prog);
125                 }
126             }
127             cit = keys.find(token);
128             if (cit != keys.end())
129             {
130                 id = cit->second;
131             }
132             break;
133 
134         case '=':
135             token += ch;
136             if (gofor(ch, pos, prog))
137             {
138                 if (ch == '=') // !% %= 操作符
139                 {
140                     token += ch;
141                     gofor(ch, pos, prog);
142                 }
143             }
144             cit = keys.find(token);
145             if (cit != keys.end())
146             {
147                 id = cit->second;
148             }
149             break;
150 
151         case '/': // / 操作符
152             token += ch;
153             if (gofor(ch, pos, prog))
154             {
155                 if (ch == '=') // /= 操作符
156                 {
157                     token += ch;
158                     gofor(ch, pos, prog);
159                 }
160                 else if (ch == '/') // 单行注释
161                 {
162                     token += ch;
163                     ++pos;
164                     while (pos < prog.size())
165                     {
166                         ch = prog[pos];
167                         if (ch == '\n')
168                         {
169                             break;
170                         }
171                         token += ch;
172                         ++pos;
173                     }
174                     if (pos >= prog.size())
175                     {
176                         ;
177                     }
178                     else
179                     {
180                         ;
181                     }
182                     id = keys.size() - 2;
183                     break;
184                 }
185                 else if (ch == '*') // 注释
186                 {
187                     token += ch;
188                     if (!gofor(ch, pos, prog))
189                     {
190                         token += "\n!!!注释错误!!!";
191                         id = -10;
192                         break;
193                     }
194                     if (pos + 1 >= prog.size())
195                     {
196                         token += ch;
197                         token += "\n!!!注释错误!!!";
198                         id = -10;
199                         break;
200                     }
201                     char xh = prog[pos + 1];
202                     while (ch != '*' || xh != '/')
203                     {
204                         token += ch;
205                         if (ch == '\n')
206                         {
207                             ++row;
208                         }
209                         //++pos;
210                         if (!gofor(ch, pos, prog))
211                         {
212                             token += "\n!!!注释错误!!!";
213                             id = -10;
214                             ret.token = token;
215                             ret.id    = id;
216                             return ret;
217                         }
218                         //ch = prog[pos];
219                         if (pos + 1 >= prog.size())
220                         {
221                             token += ch;
222                             token += "\n!!!注释错误!!!";
223                             id = -10;
224                             ret.token = token;
225                             ret.id    = id;
226                             return ret;
227                         }
228                         xh = prog[pos + 1];
229                     }
230                     token += ch;
231                     token += xh;
232                     pos += 2;
233                     ch = prog[pos];
234                     id = keys.size() - 2;
235                     break;
236                 }
237             }
238             cit = keys.find(token);
239             if (cit != keys.end())
240             {
241                 id = cit->second;
242             }
243             break;
244         case '+':
245             token += ch;
246             cit = keys.find(token);
247             if (cit != keys.end())
248             {
249                 id = cit->second;
250             }
251             gofor(ch, pos, prog);
252             break;
253 
254         case '<':
255             token += ch;
256             if (gofor(ch, pos, prog))
257             {
258                 if (ch == '<')
259                 {
260                     token += ch;
261                     if (gofor(ch, pos, prog))
262                     {
263                         if (ch == '=')
264                         {
265                             token += ch;
266                             gofor(ch, pos, prog);
267                         }
268                     }
269                 }
270                 else if (ch == '=')
271                 {
272                     token += ch;
273                     gofor(ch, pos, prog);
274                 }
275             }
276             cit = keys.find(token);
277             if (cit != keys.end())
278             {
279                 id = cit->second;
280             }
281             break;
282 
283         case '>':
284             token += ch;
285             if (gofor(ch, pos, prog))
286             {
287                 if (ch == '>')
288                 {
289                     token += ch;
290                     if (gofor(ch, pos, prog))
291                     {
292                         if (ch == '=')
293                         {
294                             token += ch;
295                             gofor(ch, pos, prog);
296                         }
297                     }
298                 }
299                 else if (ch == '=')
300                 {
301                     token += ch;
302                     gofor(ch, pos, prog);
303                 }
304             }
305             cit = keys.find(token);
306             if (cit != keys.end())
307             {
308                 id = cit->second;
309             }
310             break;
311          case '(': // / 操作符
312             token += ch;
313             if (gofor(ch, pos, prog))
314 
315             {
316                  if (ch == '*') // 注释
317                 {
318                     token += ch;
319                     if (!gofor(ch, pos, prog))
320                     {
321                         token += "\n!!!注释错误!!!";
322                         id = -10;
323                         break;
324                     }
325                     if (pos + 1 >= prog.size())
326                     {
327                         token += ch;
328                         token += "\n!!!注释错误!!!";
329                         id = -10;
330                         break;
331                     }
332                     char xh = prog[pos + 1];
333                     while (ch != '*' || xh != ')')
334                     {
335                         token += ch;
336                         if (ch == '\n')
337                         {
338                             ++row;
339                         }
340                         //++pos;
341                         if (!gofor(ch, pos, prog))
342                         {
343                             token += "\n!!!注释错误!!!";
344                             id = -10;
345                             ret.token = token;
346                             ret.id    = id;
347                             return ret;
348                         }
349                         //ch = prog[pos];
350                         if (pos + 1 >= prog.size())
351                         {
352                             token += ch;
353                             token += "\n!!!注释错误!!!";
354                             id = -10;
355                             ret.token = token;
356                             ret.id    = id;
357                             return ret;
358                         }
359                         xh = prog[pos + 1];
360                     }
361                     token += ch;
362                     token += xh;
363                     pos += 2;
364                     ch = prog[pos];
365                     id = keys.size() - 2;
366                     break;
367                 }
368             }
369             cit = keys.find(token);
370             if (cit != keys.end())
371             {
372                 id = cit->second;
373             }
374             break;
375 
376         case '*':
377             token += ch;
378             cit = keys.find(token);
379             if (cit != keys.end())
380             {
381                 id = cit->second;
382             }
383              gofor(ch, pos, prog);
384             break;
385 
386         case ',':
387         case '#':
388         case '.':
389         case ';':
390             token += ch;
391             gofor(ch, pos, prog);
392             //++pos;
393             //ch = prog[pos];
394             cit = keys.find(token);
395             if (cit != keys.end())
396             {
397                 id = cit->second;
398             }
399             break;
400 
401         case '\n':
402             token += "换行";
403             ++pos;
404             ch = prog[pos];
405             id = -2;
406             break;
407         default:
408             token += "错误";
409             ++pos;
410             ch = prog[pos];
411             id = -1;
412             break;
413         }
414     }
415     ret.token = token;
416     ret.id    = id;
417 
418     return ret;
419 }
420 
421 void init_keys(const string& file, map<string, int>& keys)//读取单词符号和种别码
422 {
423     ifstream fin(file.c_str());//.c_str返回的是当前字符串的首地址
424     if (!fin)
425     {
426         cerr << file << " doesn't exist!" << endl;//cerr不经过缓冲而直接输出,一般用于迅速输出出错信息
427       //  exit(1);
428     }
429     keys.clear();//清空map对象里面的内容
430     string line;
431     string key;
432     int id;
433     while (getline(fin, line))//这个函数接收两个参数:一个输入流对象和一个string对象,getline函数从输入流的下一行读取,并保存读取的内容到string中
434     {
435         istringstream sin(line);//istringstream sin(s);定义一个字符串输入流的对象sin,并调用sin的复制构造函数,将line中所包含的字符串放入sin 对象中!
436         sin >> key >> id;//读取里面的字符串每一行一个key id
437         keys[key] = id;
438     }
439 }
440 
441 void read_prog(const string& file, string& prog){//读取代码,并追加到prog上
442     ifstream fin(file.c_str());
443     if (!fin)
444     {
445         cerr << file << " error!" << endl;
446       //  exit(2);
447     }
448     prog.clear();
449     string line;
450     while (getline(fin, line))
451     {
452         prog += line + '\n';
453     }
454 }
455 int main()
456 {
457     map<string, int> keys;
458     init_keys("D:/Test/a.txt", keys);
459 
460     string prog;
461     read_prog("D:/Test/b.txt", prog);
462 
463     vector< _2tup > tups;
464     string token, id;
465 
466     string::size_type pos = 0;//size_type属于string标准库,作用可看做相当于unsigned·int
467     int row  = 1;
468 
469     _2tup tu;
470     cout << "------------------" << "要分析的代码如下"<< "---------------" << endl;
471     cout << prog << endl << endl;
472 
473     // prog += "#"; // 标识终止,其实可以检测 pos 来判别是否终止
474 
475     int no = 0;
476  cout << "------------------" << "分析的结果如下如下"<< "---------------" << endl;
477     do
478     {
479         tu = scanner(prog, pos, keys, row);
480 
481         switch (tu.id)
482         {
483         case -1://返回的是错误
484             ++no;
485             cout << no << ": ";
486             cout << "Error in row" << row << "!" << '<' << tu.token<< "," << tu.id << '>' << endl;
487             tups.push_back(tu);
488             break;
489         case -2:
490             ++row;
491             // cout << '<' << tu.token<< "," << tu.id << '>' << endl;
492             break;
493         default:
494             ++no;
495             cout << no << ": ";
496             if(tu.id==28 || tu.id==29){
497                 cout << '<' << tu.id<< "," << tu.token << '>' << endl;
498             }
499             else{
500                 cout << '<' << tu.id<< "," << "-" << '>' << endl;
501             }
502             tups.push_back(tu);
503             break;
504         }
505     } while (pos < prog.size());
506 
507     cout << endl << "--------------------------------结果总行数------------"<<tups.size() << endl;
508     return 0;
509 }
View Code

四:运行截图

PL/0语言词法分析器

看懂代码之后,便可以很容易扩展写出其他语言的词法分析器。