PL/0语言词法分析器

前言:关于词法分析的基础知识的介绍可以看一下这篇博客,我再累述估计也不会有这篇讲的清楚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) 识别诸如begin,end,if,while等关键字;

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

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

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

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

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

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

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

三:代码实现

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

 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.

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

 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

实现代码如下

  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 }

四:运行截图

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

原文地址:https://www.cnblogs.com/henuliulei/p/10597281.html

时间: 2024-10-13 18:59:40

PL/0语言词法分析器的相关文章

编译原理 实验1 PL/0语言词法分析

PL/0语言词法分析 一. 实验目的 通过完成词法分析程序,了解词法分析的过程.编制一个读单词程序,对PL/0语言进行词法分析,把输入的字符串形式的源程序分割成一个个单词符号,即基本保留字.标识符.常数.运算符.界符五大类. 二. 实验环境 操作系统:window xp 编写环境:visual c++ .c-free.turbo c 编写语言:c语言 分析语言:PL/0 三. 实验内容 对PL/0语言进行词法分析,把输入的字符串形式的源程序分割成一个个单词符号,其词法描述如下: (1) 关键字:

PL/0语言编译程序设计1(C语言)

本文地址:http://www.cnblogs.com/archimedes/p/pl0-compiler1.html,转载请注明源地址. PL/0简介 以下内容摘自维基: PL/0,is similar to but much simpler than the general-purpose programming language Pascal, intended as an educational programming language. It serves as an example

PL/0语言编译器的设计与实现

一.设计任务 1.1程序实现要求 PL/0语言可以看成PASCAL语言的子集,它的编译程序是一个编译解释执行系统.PL/0的目标程序为假想栈式计算机的汇编语言,与具体计算机无关. PL/0的编译程序和目标程序的解释执行程序都是用JAVA语言书写的,因此PL/0语言可在配备JDK的任何机器上实现. 其编译过程采用一趟扫描方式,以语法分析程序为核心,词法分析和代码生成程序都作为一个独立的过程,当语法分析需要读单词时就调用词法分析程序,而当语法分析正确需要生成相应的目标代码时,则调用代码生成程序. 用

PL/0编译程序

Pl/0语言文法的BNF表示: 〈程序〉→〈分程序>. 〈分程序〉→ [<常量说明部分>][<变量说明部分>][<过程说明部分>]〈语句〉 <常量说明部分> → CONST<常量定义>{ ,<常量定义>}: <常量定义> → <标识符>=<无符号整数> <无符号整数> → <数字>{<数字>} <变量说明部分> → VAR<标识符>{

PL/0与Pascal-S编译器程序详细注释

学校编译课的作业之一,要求阅读两个较为简单的编译器的代码并做注释, 个人感觉是一次挺有意义的锻炼, 将自己的心得分享出来与一同在进步的同学们分享. 今后有时间再做进一步的更新和总结,其中可能有不少错误,也请各位大佬不吝指正. 代码可以通过使用Lazarus等pascal环境执行. 源码仓库:https://github.com/luxiaodou/PL-0-and-Pascal-S-complier-trans PL0编译器源码 PL0语言是Pascal的一个子集,编译器也比较简单,逐行注释 p

C语言词法分析器

概述 词法分析是编译阶段的第一步.这个阶段的任务是从左到右一个字符一个字符地读入源程序,即对构成源程序的字符流进行扫描然后根据构词规则识别单词(也称单词符号或符号).词法分析程序实现这个任务.词法分析程序可以使用Lex等工具自动生成. 本项目实现了一个简单C语言词法分析器.现已托管在[email protected]网站上,主页:http://git.oschina.net/kinegratii/Lexer 项目特性 支持十进制数.八进制数.标识符.关键字.操作符.分隔符等多种词素 支持文件导入

浅谈PL/SQL语言基础

在前面的学习中,我们大部分接触的都是SQL语言,但是,在实现复杂操作的时候,SQL语言就无能为力了,这时候就需要引入新的语言,PL/SQL语言就是对SQL语言的扩展,可以实现存储过程,函数等的创建.下面是我对PL/SQL语言的总结,和大家分享一下. 一.基本结构 1.PL/SQL是一种块结构的语言,它将一组语句放在一个块中,一次性发送给服务器,当PL/SQL引擎分析收到PL/SQL语句块中的内容,把其中的过程语句由PL/SQL引擎自身去执行,把PL/SQL语句块中的SQL语句交给服务器的SQL语

Java编写的C语言词法分析器

这是java编写的C语言词法分析器,我也是参考很多代码,然后核心代码整理起来,放在QQ空间和博客上,目的是互相学习借鉴,希望可以得到高手改进.这个词法分析器实现的功能有打开文件.保存文件.打开帮助文档.文本域内容的剪切和复制和黏贴.进行词法分析 程序的项目结构如图,Word类和Unidentifiable类是两个JavaBean类,存放的参数有两个row(整型).word(String),row用于获取行数,word用于获取标识符,LexerFrame是词法分析器的界面类,Analyze封装了进

C# 7.0 语言新特性

下面是关于在C#7.0语言中计划功能的说明.其中大部分功能在Visual Studio “15” Preview 4中能运行.现在是最好的试用时期,请记录下你们的想法. C#7.0语言增加了许多的新功能,促使专注于数据消费,简化代码和性能. 或许最大的特征是元组(tuples) ,使得它易于有多个结果,并从而简化代码是以对数据的形状为条件的模式匹配.但也有许多其他的一些功能希望将它们结合起来,让代码运行更高效,更明确,从而获得更多的创造性.如果有哪些运行不是你想要的或者有想改进的功能,在Visu