• 【编译原理实验】 -- 词法分析程序设计原理与实现(C语言实现)


    目录

    目标任务

    设计要求

    一、程序功能描述

    二、正则文法

    三、程序结构描述

    四、代码

     五、程序测试

     测试用例1

    测试结果1

    测试用例2

    测试结果2


    目标任务

    以下为正则文法所描述的 C 语言子集单词符号的示例,请补充单词符号:++,--, >>, <<, += , -= ,*=, /= ,&&(逻辑与),||(逻辑或),!(逻辑非)等等,给出补充后描述 C 语言子集单词符号的正则文法,设计并实现其词法分析程序。

    <标识符>→字母︱ <标识符>字母︱ <标识符>数字

    <无符号整数>→数字︱ <无符号整数>数字

    <单字符分界符> →+ ︱- ︱* ︱;︱, ︱(︱) ︱{︱} <双字符分界符>→<大于>=︱<小于>=︱<小于>>︱<感叹号>=︱<等于>=︱<斜竖>*

    <小于>→<

    <等于>→=

    <大于>→>

    <斜竖> →/

     <感叹号>→!

    该语言的保留字 :void、int、float、double、if、else、for、do、while 等等(也可补充)。

    设计要求

    1)可将该语言设计成大小写不敏感,也可设计成大小写敏感,用户定义的标识符最长不超过 32 个字符;

    (2)字母为 a-z A-Z,数字为 0-9;

    (3)可以对上述文法进行扩充和改造;

    (4)“/*……*/”和“//”(一行内)为程序的注释部分。

    (5)给出各单词符号的类别编码;

    (6)词法分析程序应能发现输入串中的错误;

    (7)词法分析作为单独一遍编写,词法分析结果为二元式序列组成的中间文件;

    (8)设计两个测试用例(尽可能完备),并给出测试结果。
     


    一、程序功能描述

    输入源程序,词法分析后,能发现其中的错误;

    能够识别注释的开始结束、单字符分界符、双字符分界符;

    分析结果为二元式序列组成的中间文件。

    二、正则文法

    G[<单词符号>]:

    <单词符号>→<标识符>|<无符号整数>|<单字符分界符>|<双字符分界符>

    <标识符>→字母|<标识符>字母|<标识符>数字

    <无符号整数>→数字|<无符号整数>数字

    <单字符分界符>→% | ; | , | ( | ) | { | } | [ | ]

    <双字符分界符>→<大于>=|<小于>=|<感叹号>=|<等于>=|<斜号>*|<加号>+|<加号>=|<减号>-|<减号>=|<星号>=|<斜竖>=|<大于>>|<小于><|<与符号>&|<或符号>| |<斜号>/|<星号>/

    <小于>→<              <等于>→=            <大于>→>              <感叹号>→!

    <斜号>→/                <加号>→+             <减号>→-               <星号>→*

    <与符号>→&           <或符号>→|

    三、程序结构描述

    设计方法

    单词符号类别编码

    单词符号

    类别编码

    单词符号

    类别编码

    标识符

    1

    %

    20

    无符号整数

    2

    ;

    21

    void

    3

    ,

    22

    int

    4

    (

    23

    float

    5

    )

    24

    double

    6

    {

    25

    If

    7

    }

    26

    else

    8

    [

    27

    for

    9

    ]

    28

    do

    10

    >

    29

    while

    11

    <

    30

    return

    12

    =

    31

    break

    13

    !

    32

    continue

    14

    >=

    33

    char

    15

    <=

    34

    +

    16

    !=

    35

    -

    17

    ==

    36

    *

    18

    ++

    37

    /

    19

    --

    38

    +=

    39

    <<

    44

    -=

    40

    &&

    45

    *=

    41

    ||

    46

    /=

    42

    &

    47

    >>

    43

    |

    48

    状态转换图

    函数定义及函数之间的调用关系

    isLetter:判断是否是字母a-z,A-Z

    isDigit:判断是否是数字0-9

    getIdentifier_ID:返回保留字或标识符编号

    getSinglechar_ID:返回单字符分界符编号

    四、代码

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. int isLetter(char c){
    5. if((c>='a'&&c<='z')||(c>='A'&&c<='Z')) return 1;
    6. return 0;
    7. }
    8. int isDigit(char c){
    9. if(c>='0'&&c<='9') return 1;
    10. return 0;
    11. }
    12. int getIdentifier_ID(char s[]){
    13. if(strcmp(s,"void")==0) return 3;
    14. else if(strcmp(s,"int")==0) return 4;
    15. else if(strcmp(s,"float")==0) return 5;
    16. else if(strcmp(s,"double")==0) return 6;
    17. else if(strcmp(s,"if")==0) return 7;
    18. else if(strcmp(s,"else")==0) return 8;
    19. else if(strcmp(s,"for")==0) return 9;
    20. else if(strcmp(s,"do")==0) return 10;
    21. else if(strcmp(s,"while")==0) return 11;
    22. else if(strcmp(s,"return")==0) return 12;
    23. else if(strcmp(s,"break")==0) return 13;
    24. else if(strcmp(s,"continue")==0) return 14;
    25. else if(strcmp(s,"char")==0) return 15;
    26. else return 1;//是标识符
    27. }
    28. int getSinglechar_ID(char c){
    29. if(c==';') return 21;
    30. else if(c=='%') return 20;
    31. else if(c==',') return 22;
    32. else if(c=='(') return 23;
    33. else if(c==')') return 24;
    34. else if(c=='{') return 25;
    35. else if(c=='}') return 26;
    36. else if(c=='[') return 27;
    37. else if(c==']') return 28;
    38. else return 0;//非单字符
    39. }
    40. int main(){
    41. FILE *fp=NULL;//输入文件
    42. fp=fopen("demo_in.txt","r");
    43. FILE *fw=NULL;//输出文件
    44. fw=fopen("demo_out.txt","w");
    45. char ch;//接收字符
    46. char s1[32];//标识符
    47. char s2[32];//无符号整数
    48. int i=0;
    49. int id;
    50. int flag=0;
    51. ch=fgetc(fp);
    52. while(!feof(fp)){
    53. if(ch==' '||ch=='\t'){//为空格或制表符则不处理,获取下一个字符
    54. ch=fgetc(fp);
    55. continue;
    56. }else if(ch=='\n'){
    57. fprintf(fw,"\n");
    58. ch=fgetc(fp);
    59. continue;
    60. }else if(isLetter(ch)==1){//标识符
    61. i=0;
    62. s1[i++]=ch;
    63. while(isLetter(ch)==1||isDigit(ch)==1){
    64. ch=fgetc(fp);
    65. s1[i++]=ch;
    66. }
    67. s1[i-1]='\0';
    68. id=getIdentifier_ID(s1);
    69. fprintf(fw,"(%d,%s)",id,s1);
    70. }else if(isDigit(ch)==1){//无符号整数
    71. i=0;
    72. s2[i++]=ch;
    73. while(isDigit(ch)==1){
    74. ch=fgetc(fp);
    75. s2[i++]=ch;
    76. }
    77. s2[i-1]='\0';
    78. fprintf(fw,"(2,%s)",s2);
    79. }else if(getSinglechar_ID(ch)!=0){//单字符分界符
    80. fprintf(fw,"(%d,%c)",getSinglechar_ID(ch),ch);
    81. ch=fgetc(fp);
    82. }else if(ch=='>'){//大于
    83. ch=fgetc(fp);
    84. if(ch=='='){
    85. fprintf(fw,"(33,>=)");
    86. ch=fgetc(fp);
    87. }else if(ch=='>'){
    88. fprintf(fw,"(43,>>)");
    89. ch=fgetc(fp);
    90. }else{
    91. fprintf(fw,"(29,>)");
    92. }
    93. }else if(ch=='<'){//小于
    94. ch=fgetc(fp);
    95. if(ch=='='){
    96. fprintf(fw,"(34,<=)");
    97. ch=fgetc(fp);
    98. }else if(ch=='<'){
    99. fprintf(fw,"(44,<<)");
    100. ch=fgetc(fp);
    101. }else{
    102. fprintf(fw,"(30,<)");
    103. }
    104. }else if(ch=='!'){//感叹号
    105. ch=fgetc(fp);
    106. if(ch=='='){
    107. fprintf(fw,"(35,!=)");
    108. ch=fgetc(fp);
    109. }else{
    110. fprintf(fw,"(32,!)");
    111. }
    112. }else if(ch=='='){//等于
    113. ch=fgetc(fp);
    114. if(ch=='='){
    115. fprintf(fw,"(36,==)");
    116. ch=fgetc(fp);
    117. }else{
    118. fprintf(fw,"(31,=)");
    119. }
    120. }else if(ch=='/'){//斜号
    121. ch=fgetc(fp);
    122. if(ch=='*'){
    123. fprintf(fw,"(处理注释,/*)");
    124. while(1){
    125. flag=0;
    126. ch=fgetc(fp);
    127. while(ch=='*'){//不用if,while可以处理/*后多个*的问题
    128. ch=fgetc(fp);
    129. if(ch=='/'){
    130. fprintf(fw,"(注释结束,*/)");
    131. ch=fgetc(fp);
    132. flag=1;
    133. }
    134. }
    135. if(flag==1) break;
    136. }
    137. }else if(ch=='/'){
    138. fprintf(fw,"(处理注释,//)");
    139. while(ch!='\n'){
    140. ch=fgetc(fp);
    141. }
    142. fprintf(fw,"\n");
    143. ch=fgetc(fp);
    144. }else if(ch=='='){
    145. fprintf(fw,"(42,/=)");
    146. ch=fgetc(fp);
    147. }else{
    148. fprintf(fw,"(19,/)");
    149. }
    150. }else if(ch=='&'){//与符号
    151. ch=fgetc(fp);
    152. if(ch=='&'){
    153. fprintf(fw,"(45,&&)");
    154. ch=fgetc(fp);
    155. }else{
    156. fprintf(fw,"(47,&)");
    157. }
    158. }else if(ch=='|'){//或符号
    159. ch=fgetc(fp);
    160. if(ch=='|'){
    161. fprintf(fw,"(46,||)");
    162. ch=fgetc(fp);
    163. }else{
    164. fprintf(fw,"(48,|)");
    165. }
    166. }else if(ch=='+'){//加号
    167. ch=fgetc(fp);
    168. if(ch=='='){
    169. fprintf(fw,"(39,+=)");
    170. ch=fgetc(fp);
    171. }else if(ch=='+'){
    172. fprintf(fw,"(37,++)");
    173. ch=fgetc(fp);
    174. }else{
    175. fprintf(fw,"16,+");
    176. }
    177. }else if(ch=='-'){//减号
    178. ch=fgetc(fp);
    179. if(ch=='='){
    180. fprintf(fw,"(40,-=)");
    181. ch=fgetc(fp);
    182. }else if(ch=='-'){
    183. fprintf(fw,"(38,--)");
    184. ch=fgetc(fp);
    185. }else{
    186. fprintf(fw,"(17,-)");
    187. }
    188. }else if(ch=='*'){//星号
    189. ch=fgetc(fp);
    190. if(ch=='='){
    191. fprintf(fw,"(41,*=)");
    192. ch=fgetc(fp);
    193. }else{
    194. fprintf(fw,"(18,*)");
    195. }
    196. }else{//其他,出错
    197. fprintf(fw,"\n错误:未定义->%c",ch);
    198. printf("错误:未定义->%c\n",ch);
    199. break;
    200. }
    201. }
    202. fclose(fp);
    203. fclose(fw);
    204. printf("二元式序列组成的中间文件已经生成!\n");
    205. return 0;
    206. }

     五、程序测试

     测试用例1

     

    测试结果1

     

    测试用例2

     

    测试结果2


     如果对你有帮助的话,可以考虑点个赞~~

  • 相关阅读:
    GO sync.Map Store、Delete 、Load 、Range等方法使用举例
    高并发 发送请求(asyncio)
    Webmin远程命令执行漏洞复现报告
    java调用海康威视SDK实现车牌识别
    美团面试:Oracle JDK那么好,为何要用Open JDK?
    1688 API接口测试指南
    【再探】Java — 面向对象编程特性与内部类
    flask捕获@app.errorhandler/@app.after_request全局异常总结
    React学习3(React组件)
    免费的在线视频编辑工具,mp4转gif工具
  • 原文地址:https://blog.csdn.net/Tir_zhang/article/details/127339376