上周帮一个刚刚找到自己方向的好友做了一个编译原理的课程实验,要求是做一个词法分析器,具体要求如下:

对下述文法和单词表定义的语言设计编制一个语法分析器。

(1)单词符号及种别表

单词符号

种别编码

单词值

main

1

 

int

2

 

float

3

 

double

4

 

char

5

 

if

6

 

else

7

 

do

8

 

while

9

 

l(l|d)*

10

内部字符串

( +|-|ε ) dd*(.dd* | ε)( e ( +|-|ε ) dd*|ε)

20

二进制数值表示

=

21

 

+

22

 

-

23

 

*

24

 

/

25

 

(

26

 

)

27

 

{

28

 

}

29

 

,

30

 

;

31

 

>

32

 

>=

33

 

<

34

 

&lt;=

35

 

==

36

 

!=

37

 

(2)语法结构定义

&lt;表达式> ::= <项>{ +<项>|-<项>}

<项> ::= <因子>{*<因子>|/<因子>}

<因子> ::=ID|num|(<表达式>)

num::= ( +|-|ε ) 数字数字*(.数字数字* | ε)( e ( +|-|ε ) 数字数字*|ε)

ID::=字母(字母|数字)*

字母::=a|b|c…|z|A|B|C…|Z

数字::=0|1|2…|9

本来不是个很难的程序,但我还是写的较为复杂,有这方面心得的朋友可以和我联系,一起探讨一下吧~~~下面我把自己简陋的代码贴在下面:

  1. #include <stdio.h> 
  2. #include <stdlib.h> 
  3. #include <string.h> 
  4.  
  5. #define INVALUECHAR   '.'  //非法字符,用于给token赋初值 
  6. #define MAXCHARNUM    80   //接受字符串输入的长度 
  7. #define TOKENLENGTH   15   //词组的最大长度 
  8. #define RETABLENGTH   9    //关键字的个数 
  9. #define TRUE          0 
  10. #define FALSE         -1 
  11.  
  12. int  syn, sum = 0; 
  13. char token[TOKENLENGTH] = { '\0' }; //记录找到的词组 
  14. char *rwtab[RETABLENGTH] = { "main""int""float""double""char""if""else""do""while" }; //记录关键字 
  15.  
  16. int IsNumber(char num); //判断num是否为数字 
  17. int GetSum(int i); //求token前i个数的加权和 
  18. int HoldE(int *local, char *string, int num, int *i); //读取浮点数时进行遇到符号e的操作 
  19. int NumberOP(int *local, char *string, int num, int *i, char c); //读取浮点数时进行遇到非数字字符的操作 
  20. int Analyze(char *string, int num); //搜寻最长字串的函数 
  21.  
  22.  
  23. int main() 
  24.     int p = 0, i, j; 
  25.     char string[MAXCHARNUM] = { '\0' }; 
  26.  
  27.     printf("please input a string:\n"); 
  28.     //读取输入的字符串,超过长度限定就让用户重新输入 
  29.     do { 
  30.         scanf("%c", &string[p++]); 
  31.         if (MAXCHARNUM <= p) { 
  32.             printf("\nYou have input more than 80 characters!\n"); 
  33.             printf("Please input again:\n"); 
  34.             string[0] = '\0'
  35.             p = 0; 
  36.         } 
  37.     }while ('\n' != string[p-1]); //字符串以'\n'结束 
  38.  
  39.     //遍历输入的字符串,忽略回车和空格 
  40.     for (i = 0; i < p; i++) { 
  41.         if ((' ' == string[i]) || ('\n' == string[i])) 
  42.             continue
  43.         else { 
  44.             j = Analyze(string, i); //当出现错误时Analyze返回FALSE,正确时返回找到字串的最后一个字符的位置 
  45.             if (FALSE == j) { 
  46.                 printf("\nYour input is wrong!\n"); 
  47.                 return 1; 
  48.             } 
  49.             i = j; //将i赋值为查找到字串的最后一个字符的位置 
  50.  
  51.             switch (syn) { 
  52.                 //-1为出现非法字符,0为正常结束,11为整型数的sum输出 
  53.                 case -1: { printf("\nYou have input illegal characters!\nSo it ended!\n");  
  54.                            break; } 
  55.                 case 0: { break; } 
  56.                 case 20: { if (0 != sum) { 
  57.                                printf("( %-5d%15d )\n", syn, sum); 
  58.                                sum = 0; 
  59.                            } 
  60.                            else 
  61.                                printf("( %-5d%15s )\n", syn, token); 
  62.                            break; } 
  63.                 default: { printf("( %-5d%15s )\n", syn, token); 
  64.                            break; } 
  65.             } 
  66.         } 
  67.     } 
  68.     return 0; 
  69.  
  70. //判断num是否为数字 
  71. int IsNumber(char num) 
  72.    if (('0' <= num) && ('9' >= num)) 
  73.        return TRUE; 
  74.    else 
  75.        return FALSE; 
  76.  
  77. //求token前i个数字的加权和 
  78. int GetSum(int i) 
  79.     int sum, j; 
  80.     char a[TOKENLENGTH]; 
  81.     for (j = 0; j < i; j++) 
  82.         a[j] = token[j]; 
  83.     a[j] = '\0'
  84.     sum = atoi(a); 
  85.     return sum; 
  86.  
  87. //读取浮点数时遇到e的处理 
  88. int HoldE(int *local, char *string, int num, int *i) 
  89.     char ch = 'e'
  90.     token[(*i)++] = ch; 
  91.     ch = string[++num]; 
  92.     //e的后一位为数字 
  93.     if (TRUE == IsNumber(ch)) { 
  94.         token[(*i)++] = ch; 
  95.         ch = string[++num]; 
  96.         while (TRUE == IsNumber(ch)) { 
  97.             token[(*i)++] = ch; 
  98.             ch = string[++num]; 
  99.         } 
  100.         *local = num - 1; //改变string中下标需要指向的位置 
  101.         return TRUE; 
  102.     } 
  103.     //e的后一位为'+'或'-' 
  104.     else if (('+' == ch) || ('-' == ch)) { 
  105.         token[(*i)++] = ch; 
  106.         ch = string[++num]; 
  107.         if (TRUE != IsNumber(ch)) 
  108.             return FALSE; 
  109.         while (TRUE == IsNumber(ch)) { 
  110.             token[(*i)++] = ch; 
  111.             ch = string[++num]; 
  112.         } 
  113.         *local = num - 1; 
  114.         return TRUE; 
  115.     } 
  116.     //其他情况就出现错误 
  117.     else 
  118.         return FALSE; 
  119.  
  120. //读取浮点数时遇到第一个非数字的字符的处理 
  121. int NumberOP(int *local, char *string, int num, int *i, char c) 
  122.     int result = TRUE; 
  123.     char ch = c; 
  124.     //这个非数字字符为小数点 
  125.     if ('.' == ch) { 
  126.         token[(*i)++] = ch; 
  127.         ch = string[++num]; 
  128.         //小数点后一位如果不是数字就出现错误 
  129.         if (TRUE != IsNumber(ch)) 
  130.             return FALSE; 
  131.         while (TRUE == IsNumber(ch)) { 
  132.             token[(*i)++] = ch; 
  133.             ch = string[++num]; 
  134.         } 
  135.         //小数点之后一串数字过后遇到e 
  136.         if ('e' == ch) { 
  137.             result = HoldE(local, string, num, i); 
  138.             if (FALSE == result) 
  139.                 return FALSE; 
  140.         } 
  141.         else 
  142.             *local = num - 1; 
  143.     } 
  144.     //这个字符为e 
  145.     else if ('e' == ch) { 
  146.         result = HoldE(local, string, num, i); 
  147.         if (FALSE == result) 
  148.             return FALSE; 
  149.     } 
  150.     //其他情况就不用再读取了,直接修改local并返回 
  151.     else  
  152.         *local = num - 1; 
  153.     syn = 20; 
  154.     return TRUE; 
  155.  
  156. //查询最长字串 
  157. int Analyze(char *string, int num) 
  158.     int m, i = 0, local = num, n, flag = 0; 
  159.     int result = TRUE; 
  160.     char ch; 
  161.  
  162.     for (m = 0; m < TOKENLENGTH; m++) 
  163.         token[m++] = INVALUECHAR; 
  164.  
  165.     ch = string[num]; 
  166.     //第一种情况为字符 
  167.     if (((ch <= 'z') && (ch >= 'a')) || ((ch <= 'Z') && (ch >= 'A'))) {  
  168.         while(((ch <= 'z') && (ch >= 'a')) || (( ch <= 'Z') && (ch >= 'A')) || (TRUE == IsNumber(ch))) { 
  169.             token[i++] = ch; 
  170.             //token长度限定 
  171.             if (i >= (TOKENLENGTH - 1)) 
  172.                 return FALSE; 
  173.             else 
  174.                 ch = string[++num]; 
  175.         } 
  176.         local = num - 1; 
  177.         //syn预设为l(l | d)*的形式 
  178.         syn = 10; 
  179.         token[i] = '\0'
  180.         //遍历关键字数组,如果找到就修改syn并 
  181.         for (n = 0; n < RETABLENGTH; n++) 
  182.             if (0 == strcmp(token, rwtab[n])) { 
  183.                 syn = n + 1; 
  184.                 break
  185.             } 
  186.     } 
  187.     //第二种情况为遇到'+'、'-'或数字 
  188.     else if (('+' == ch) || ('-' == ch) || (TRUE == IsNumber(ch))) { 
  189.         token[i++] = ch; 
  190.         //如果为数字就用flag标记一下 
  191.         if (TRUE == IsNumber(ch)) 
  192.             flag = 1; 
  193.         ch = string[++num]; 
  194.         //下一位也为数字 
  195.         if (TRUE == IsNumber(ch)) { 
  196.             token[i++] = ch; 
  197.             ch = string[++num]; 
  198.             while (TRUE == IsNumber(ch)) { 
  199.                 token[i++] = ch; 
  200.                 ch = string[++num]; 
  201.             } 
  202.             //遇到第一个 
  203.             result = NumberOP(&local, string, num, &i, ch); 
  204.             if (FALSE == result) 
  205.                 return FALSE; 
  206.         } 
  207.         //下一位不为数字要分情况,当第一位为数字时执行下列操作, 
  208.         //第一位为'+'、'-'时,下一位必须为数字 
  209.         else if (1 == flag) { 
  210.             result = NumberOP(&local, string, num, &i, ch); 
  211.             if (FALSE == result) 
  212.                 return FALSE;        
  213.         } 
  214.         //当第一位为'+'、'-'时,下一位不为数字证明'+'、'-'已经是最长的字串了 
  215.         else { 
  216.             if ('+' == token[i-1]) 
  217.                 syn = 22; 
  218.             else 
  219.                 syn = 23; 
  220.         } 
  221.     } 
  222.     else { 
  223.         switch (ch) { 
  224.             case '=': { token[i++] = ch; 
  225.                         ch = string[++num]; 
  226.                         if ('=' == ch) { 
  227.                             syn = 36; 
  228.                             token[i++] = ch; 
  229.                             local = num; 
  230.                             break
  231.                         } 
  232.                         syn = 21; 
  233.                         break; } 
  234.             case '*': { syn = 24; 
  235.                         token[i++] = ch; 
  236.                         break; } 
  237.             case '/': { syn = 25; 
  238.                         token[i++] = ch; 
  239.                         break; } 
  240.             case '(': { syn = 26; 
  241.                         token[i++] = ch; 
  242.                         break; } 
  243.             case ')': { syn = 27; 
  244.                         token[i++] = ch; 
  245.                         break; } 
  246.             case '{': { syn = 28; 
  247.                         token[i++] = ch; 
  248.                         break; } 
  249.             case '}': { syn = 29; 
  250.                         token[i++] = ch; 
  251.                         break; } 
  252.             case ',': { syn = 30; 
  253.                         token[i++] = ch; 
  254.                         break; } 
  255.             case ';': { syn = 31; 
  256.                         token[i++] = ch; 
  257.                         break; } 
  258.             case '>': { token[i++] = ch; 
  259.                         ch = string[++num]; 
  260.                         if ('=' == ch) { 
  261.                             syn = 33; 
  262.                             token[i++] = ch; 
  263.                             local = num; 
  264.                             break
  265.                         } 
  266.                         syn = 32; 
  267.                         break; } 
  268.             case '<': { token[i++] = ch; 
  269.                         ch = string[++num]; 
  270.                         if ('=' == ch) { 
  271.                             syn = 35; 
  272.                             token[i++] = ch; 
  273.                             local = num; 
  274.                             break
  275.                         } 
  276.                         syn = 34; 
  277.                         break; } 
  278.             case '!': { token[i++] = ch; 
  279.                         ch = string[++num]; 
  280.                         if ('=' != ch) { 
  281.                             return FALSE; 
  282.                         } 
  283.                         syn = 37; 
  284.                         token[i++] = ch; 
  285.                         local = num; 
  286.                         break; } 
  287.             case '\n': { syn = 0; 
  288.                          token[i++] = ch; 
  289.                          break; } 
  290.             default: { syn = -1; 
  291.                        break; } 
  292.         } 
  293.     } 
  294.     token[i] = '\0'
  295.     return local;