Liny_@NotePad

沉迷ACG中

简单PL/0词法分析

YOYO posted @ 2009年4月29日 08:40 in 【C/C++】 with tags 编译原理 词法分析 , 5539 阅读

一、功能描述:
编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号。(遇到错误时可显示“Error”,然后跳过错误部分继续显示)。

二、定义:
识别保留字:var、const、begin、end、while、do、read、
write、if、then、procedure、call
其他的都识别为标识符;
常数为无符号整形数;
运算符包括:+ - * / = > < >= <= #
分隔符包括:,   ;   (    )
Pl/0源程序由“.”结束。

三、程序结构描述:
 全局变量:
set<string> sys;   —— 存储系统保留字集合
set<char> opChar1;  —— 存储运算符的第一个字符集合
map<char,string> split; —— 存储分隔符
map<string,string> op;  —— 存储运算符

程序分成如下几个函数:
 void init() ——初始化函数
初始化各个类型中可能出现的值,即初始化识别保留字、运算符和分隔符的集合。

 void println(string s, char ch)、void println(string s1, string s2)  打印函数
 void printlnError()——打印错误信息

 bool isNumber(char ch) ——判定一个字符是否是数字
 bool isNumber(string s) ——判定一个字符串是否是整数
 bool isLetter(char ch) ——判定一个字符是否是字母
 bool isIdent(string s) ——判定一个字符串是否是标识符

 void splitWord(string &str, char ch = 0) ——划分单词
传入一个字符ch,如果它是运算符或分隔符的第一个字符,或者是0(表示到了行尾),是则解析存储于公共变量str的字符串输出,同时判定该字符是否是一个分隔符。如果不是则将该字符添加到公共变量str的末尾,再次判定字符串是否是运算符,如果不是则留待下次解析。

 void readFile(string filePath) ——读取文件内容
传入一个字符串filePath,用来指定要打开的文件名。打开文件读入字符串直到文件结束或读到字符串为“.”。对每个字符串,从第一个字符开始调用splitWord函数解析单词,直到字符串都拆解完毕。

 main ——主函数
处理输入文件名的部分,若输入为“q”则退出循环,否则对指定文件进行词法分析。

 

程序总体执行流程图

 

 

 

拆分单词流程图

四、实验总结:
完成总使用四课时:
其中纸上时间 一课时,编程一课时,调试两课时。

问题:

  •  刚开始时考虑欠缺,只考虑到了各个单词间会有空格符分隔开来的情况,导致当输入形如“a=b”这类将单词连接起来的语句时就会出错。

  在每次输入字符串时,细化到对字符串中的各个字符逐步进行解析。

  • 未考虑到“:=”、“>=”、“<=”这种不止一个字符的运算符的情况。

  多写了一层判定。

  • 未考虑到代码是否违法。

  增加了对是否是合法数字和合法标识符的判定,
另外在”.”后面若还有内容也判定为错误(即使是空行 = =)。

 评价:
 程序中的判定过多,目的不够明确,需要重构。
 由于没有做好纸上设计,导致中途发现较多错误,调试时间过长。

 收获:
 了解到一些词法分析的知识,但还需要理解书后的代码以提高水平。

* 附件1:程序源码

  1. #include<iostream>
  2. #include<fstream>
  3. #include<string>
  4. #include<map>
  5. #include<set>
  6. using namespace std;
  7.  
  8. set<string> sys;                //      存储系统保留字集合
  9. set<char> opChar1;            //    存储运算符首字符
  10.  
  11. map<char,string> split; //       存储分隔符集合
  12. map<string,string> op;  //        存储运算符集合
  13.  
  14. /*      初始化集合       */
  15. void init(){
  16.         //      初始化系统保留字集合
  17.         sys.insert("var");
  18.         sys.insert("begin");
  19.         sys.insert("end");
  20.         sys.insert("read");
  21.         sys.insert("write");
  22.         sys.insert("const");
  23.         sys.insert("do");
  24.         sys.insert("if");
  25.         sys.insert("then");
  26.         sys.insert("procedure");
  27.         sys.insert("call");
  28.  
  29.         //      存储运算符首字符
  30.         opChar1.insert('+');
  31.         opChar1.insert('-');
  32.         opChar1.insert('*');
  33.         opChar1.insert('/');
  34.         opChar1.insert('#');
  35.         opChar1.insert('=');
  36.         opChar1.insert(':');
  37.         opChar1.insert('>');
  38.         opChar1.insert('<');
  39.  
  40.         //      初始化分隔符集合
  41.         split[',']="comma";
  42.         split[';']="semicolon";
  43.         split['(']="lparen";
  44.         split[')']="rparen";
  45.         split['.']="period";
  46.  
  47.         //      初始化运算符集合
  48.         op["+"]="plus";
  49.         op["-"]="minus";
  50.         op["*"]="multiply";
  51.         op["/"]="divide";
  52.         op["="]="equal";
  53.         op[">"]="greater";
  54.         op["<"]="less";
  55.         op[":="]="becomes";
  56.         op[">="]="ge";
  57.         op["<="]="le";
  58.         op["#"]="#";
  59. }
  60.  
  61. /*      打印错误信息    */
  62. void printError(){
  63.         cout<<"Error"<<endl;
  64. }
  65.  
  66. /*      打印字符串类型 */
  67. void println(string s1, string s2){
  68.         cout<<s1<<", \""<<s2<<"\""<<endl;
  69. }
  70.  
  71. /*      打印字符类型    */
  72. void println(string s, char ch){
  73.         cout<<s<<", \""<<ch<<"\""<<endl;
  74. }
  75.  
  76. /*      判断是否是一个数字字符     */
  77. bool isNumber(char ch){
  78.         return ch>='0'&&ch<='9';
  79. }
  80.  
  81. /*      判断是否是一个数字字符串  */
  82. bool isNumber(string str){
  83.         for(int i=0; i<str.size(); i++){
  84.                 if(!isNumber(str[i])){
  85.                         return false;
  86.                 }
  87.         }
  88.         return true;
  89. }
  90.  
  91. /*      判断是否是一个字母   */
  92. bool isLetter(char ch){
  93.         if(ch>='A'&&ch<='Z')return true;
  94.         if(ch>='a'&&ch<='z')return true;
  95.         return false;
  96. }
  97.  
  98. /*      判断是否是一个标识符字符串       */
  99. bool isIdent(string str){
  100.         if(!isLetter(str[0]))return false;      //    标识符首字符应是字母
  101.         for(int i=1; i<str.size(); i++){        //      标识符其他字符应是字母或数字
  102.                 if(!isLetter(str[i])&&!isNumber(str[i])){
  103.                         return false;
  104.                 }
  105.         }
  106.         return true;
  107. }
  108.  
  109. /*      词法分析  */
  110. void splitWord(string &str, char ch = 0){
  111.         if(ch==0||opChar1.find(ch)!=opChar1.end()||split.find(ch)!=split.end()){
  112.                                                         //      若输入字符是行尾/运算符首字符/分隔符 则
  113.                 if(str.size()>0){       //     若保存的字符串不为空 则
  114.                         if(sys.find(str)!=sys.end()){   // 若字符串是系统保留字 输出
  115.                                 println(str+"sys", str);
  116.                         }else{      //        否则判断 字符是否是“=”,而保留的串是“:><”中的一种(运算符的首字符)
  117.                                 if(ch=='='&&str.size()==1&&(string(":><").find(str))>=0){
  118.                                         str = str.append(1,ch)//       是则输出该运算符类型
  119.                                         println(op[str],str);
  120.                                         str="";     //       清空保留的串并返回
  121.                                         return;
  122.                                 }
  123.                                 if(isNumber(str)){                  //    判断该字符串是否是数字 是则输出
  124.                                         println("number",str);
  125.                                 }else{
  126.                                         if(isIdent(str)){              //     否则判断该字符串是否是合法的标识符,是则输出
  127.                                                 println("ident",str);
  128.                                         }else{
  129.                                                 printError();      // 否则报错
  130.                                         }
  131.                                 }
  132.                         }
  133.                         str = "";              //     清空字符串
  134.                 }
  135.                 if(split.find(ch)!=split.end()){        //      该字符是否是分隔符
  136.                         println(split[ch],ch);      //        打印分隔符并返回
  137.                         str="";
  138.                         return;
  139.                 }
  140.         }
  141.         str = str.append(1,ch);  //       都不是则将字符存到字符串末尾
  142.         if(op.find(str)!=op.end()){     //   判定该字符是否是运算符 是则输出
  143.                 if(str.size()==1&&(str[0]=='>'||str[0]=='<'))return;
  144.                 println(op[str],str);
  145.                 str="";
  146.         }
  147. }
  148.  
  149. /*      读取指定的文件内容并对其进行词法分析        */
  150. void readFile(string filePath){
  151.         fstream file;
  152.         file.open(filePath.c_str(),ios_base::in);
  153.  
  154.         if(!file){            //    如果文件不存在则报错并返回
  155.                 printError();
  156.                 return;
  157.         }
  158.  
  159.         char ch;
  160.         string s, str;
  161.         while(file>>s){ //       从文件中读取字符串
  162.                 for(int i=0; i<s.size(); i++){  //        对每个字符进行分析
  163.                         ch = s[i];
  164.                         splitWord(str, ch);
  165.                 }
  166.                 splitWord(str);   //       最后再进行一次词法分析
  167.                 if(str==".")break;            //    当最后为“.”时退出循环
  168.                 if(str[0])printError()//       若一行未解析完毕 表示有错误不能解析 报错
  169.                 str="";     //       清空该行字符串
  170.         }
  171.  
  172.         if(file>>s){                //  若遇到“.”后还可以读入 报错
  173.                 cout<<"Error"<<endl;
  174.         }
  175. }
  176.  
  177. /***主函数***/
  178. int main(){
  179.         init();
  180.         string filePath;
  181.  
  182.         while(true){
  183.                 cout<<"please input filePath(enter q to quit): ";
  184.                 cin>>filePath;
  185.  
  186.                 if(filePath=="q")break;  //       如果输入q则退出
  187.  
  188.                 readFile(filePath);               //   读取文件内容并分析词法
  189.  
  190.                 cout<<endl;
  191.         }
  192.  
  193.         return 0;
  194. }

 *附件2:样例输入输出

  1. ---------------------------------------------------
  2. -       第一组输入
  3. ---------------------------------------------------
  4. var a,b;
  5. begin
  6.         a := 10;
  7.         b := a + 20;
  8.         write(b);
  9. end.
  10. ---------------------------------------------------
  11. -       第一组输出
  12. ---------------------------------------------------
  13. varsys, "var"
  14. ident, "a"
  15. comma, ","
  16. ident, "b"
  17. semicolon, ";"
  18. beginsys, "begin"
  19. ident, "a"
  20. becomes, ":="
  21. number, "10"
  22. semicolon, ";"
  23. ident, "b"
  24. becomes, ":="
  25. ident, "a"
  26. plus, "+"
  27. number, "20"
  28. semicolon, ";"
  29. writesys, "write"
  30. lparen, "("
  31. ident, "b"
  32. rparen, ")"
  33. semicolon, ";"
  34. endsys, "end"
  35. period, "."
  36. ---------------------------------------------------
  37. -       第二组输入
  38. ---------------------------------------------------
  39. const a = 10;
  40. var b,c;
  41. procedure p;
  42.         begin
  43.         c:=b+a;
  44. end;
  45. begin
  46.         read(b);
  47.         while b#0 do
  48.         begin
  49.                 call p; write(2*c); read(b);
  50.         end;
  51. end.
  52. ---------------------------------------------------
  53. -       第二组输出
  54. ---------------------------------------------------
  55. constsys, "const"
  56. ident, "a"
  57. equal, "="
  58. number, "10"
  59. semicolon, ";"
  60. varsys, "var"
  61. ident, "b"
  62. comma, ","
  63. ident, "c"
  64. semicolon, ";"
  65. proceduresys, "procedure"
  66. ident, "p"
  67. semicolon, ";"
  68. beginsys, "begin"
  69. ident, "c"
  70. becomes, ":="
  71. ident, "b"
  72. plus, "+"
  73. ident, "a"
  74. semicolon, ";"
  75. endsys, "end"
  76. semicolon, ";"
  77. beginsys, "begin"
  78. readsys, "read"
  79. lparen, "("
  80. ident, "b"
  81. rparen, ")"
  82. semicolon, ";"
  83. ident, "while"
  84. ident, "b"
  85. #, "#"
  86. number, "0"
  87. dosys, "do"
  88. beginsys, "begin"
  89. callsys, "call"
  90. ident, "p"
  91. semicolon, ";"
  92. writesys, "write"
  93. lparen, "("
  94. number, "2"
  95. multiply, "*"
  96. ident, "c"
  97. rparen, ")"
  98. semicolon, ";"
  99. readsys, "read"
  100. lparen, "("
  101. ident, "b"
  102. rparen, ")"
  103. semicolon, ";"
  104. endsys, "end"
  105. semicolon, ";"
  106. endsys, "end"
  107. period, "."
  108. ---------------------------------------------------
  109. -       第三组输入
  110. ---------------------------------------------------
  111. var x,y;
  112. procedure p;
  113. var a;
  114.         procedure q;
  115.         var b;
  116.         begin
  117.                 b:=10;
  118.         end;
  119.         procedure s;
  120.         var c,d;
  121.                 procedure r;
  122.                 var e,f;
  123.                 begin
  124.                         call q;
  125.                 end;
  126.         begin
  127.                 call r;
  128.         end;
  129. begin
  130.         call s;
  131. end;
  132. begin
  133.         call p;
  134. end.
  135. ---------------------------------------------------
  136. -       第三组输出
  137. ---------------------------------------------------
  138. varsys, "var"
  139. ident, "x"
  140. comma, ","
  141. ident, "y"
  142. semicolon, ";"
  143. proceduresys, "procedure"
  144. ident, "p"
  145. semicolon, ";"
  146. varsys, "var"
  147. ident, "a"
  148. semicolon, ";"
  149. proceduresys, "procedure"
  150. ident, "q"
  151. semicolon, ";"
  152. varsys, "var"
  153. ident, "b"
  154. semicolon, ";"
  155. beginsys, "begin"
  156. ident, "b"
  157. becomes, ":="
  158. number, "10"
  159. semicolon, ";"
  160. endsys, "end"
  161. semicolon, ";"
  162. proceduresys, "procedure"
  163. ident, "s"
  164. semicolon, ";"
  165. varsys, "var"
  166. ident, "c"
  167. comma, ","
  168. ident, "d"
  169. semicolon, ";"
  170. proceduresys, "procedure"
  171. ident, "r"
  172. semicolon, ";"
  173. varsys, "var"
  174. ident, "e"
  175. comma, ","
  176. ident, "f"
  177. semicolon, ";"
  178. beginsys, "begin"
  179. callsys, "call"
  180. ident, "q"
  181. semicolon, ";"
  182. endsys, "end"
  183. semicolon, ";"
  184. beginsys, "begin"
  185. callsys, "call"
  186. ident, "r"
  187. semicolon, ";"
  188. endsys, "end"
  189. semicolon, ";"
  190. beginsys, "begin"
  191. callsys, "call"
  192. ident, "s"
  193. semicolon, ";"
  194. endsys, "end"
  195. semicolon, ";"
  196. beginsys, "begin"
  197. callsys, "call"
  198. ident, "p"
  199. semicolon, ";"
  200. endsys, "end"
  201. period, "."

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter