2013-10-12 21 views
0

我的词法分析器可识别数字(5,555,543667),小数(44.65,4.1)和句点(。)。C词法分析器。使用开关来分析和计算小数/非小数

我可以对数字,小数点和句点进行计数,但是当我遇到一个数字和句点相邻时,它会将其计为小数。

考虑包含一个文本文件:555 2.3 55.23 44 5

我的输出将是

1类型1:555
2类型3:2.3
3类型3:55.23
4类型1:44
5类型3:5.

其中类型3是我的十进制标识符。

我想第5和第6令牌被计为一个数字,然后一个时期。

这是我如何处理我的switch语句。

switch(*b) { 

    case '0': 
    case '1': 
    case '2': 
    case '3': 
    case '4': 
    case '5': 
    case '6': 
    case '7': 
    case '8': 
    case '9': 
    digits: 
     t.length++; 
     switch(*(b + t.length)) { 
      case '0': 
      case '1': 
      case '2': 
      case '3': 
      case '4': 
      case '5': 
      case '6': 
      case '7': 
      case '8': 
      case '9': 
       goto digits; 
      case '.': 
       goto decimal;     
       break; 
      default: 
       break; 
     } 

     t.type = TOKEN_DIGITS; 
     t.string = (char *)calloc(t.length + 1, sizeof(char)); 
     strncpy(t.string, b, t.length); 
     break; 



    decimal: 
     t.length++; 
     switch(*(b + t.length)) { 
      case '0': 
      case '1': 
      case '2': 
      case '3': 
      case '4': 
      case '5': 
      case '6': 
      case '7': 
      case '8': 
      case '9': 
       goto decimal; 
       break; 
      } 
      t.type = TOKEN_DECIMAL; 
      t.string = (char *)calloc(t.length+1,sizeof(char)); 
      strncpy(t.string,b,t.length);   
     break; 

尝试了多件事,但我被正式卡住了。

+1

词汇分析不是要求大量gotos的地方。考虑一些for循环和isdigit()调用。 –

+1

gotos是邪恶的,尽量不要习惯于他们。至于这个问题,你的问题是,除非你处理完整个项目,否则你不知道这个案例。你需要首先将你的字符串分解成“单词”,后者逐个处理它们,每个单词作为一个整体(而不是逐个字符地处理)。 – SJuan76

+0

使用flex会不会更容易?如果这是一个学习练习,你学到了什么? – rici

回答

1

你真的应该使用character classification functions这种练习而不是长开关语句。你的代码会简单得多,你根本不需要使用goto

例如,数目可以用下面的正则表达式描述(加入的空白,打破了各种块):

此已经示出了可能的状态转移:

  • 甲号码可以(可选)以+-(如果您支持带符号的数字)开头
  • 它可能有0..n个数字
  • 如果下列字符不是小数点符号,它应该是分隔符,否则它是无效符号。如果是分隔符,您的号码将被终止。
  • 小数点后应该有1..1位数
  • 当你到达输入的末尾或者你遇到一个分隔符

这一切都可以在线路屈指可数完成数量被终止的代码 - 只需要一个指向你当前输入字符的指针,然后一个接一个地前进,并检查每个字符并根据字符类别决定要做什么。

现在,这种特殊的方法并不使用科学记数法等处理浮点数,但是一旦完成基础知识后,添加额外的东西就非常简单。

0

使用像digit_follow_peroid这样的变量来保持状态。每遇到一个循环时,将该变量设置为false,然后当您遇到小数点开关块中的一个数字时,将其设置为true。检查变量的值以确定t。长度在strncpy之前。也许你还需要其他变量与它一起工作。最好的方法是定义一个状态转换矩阵,它比gotos好得多。

1

我认为这是对xxbbcc的回答的补充。

* 非常粗略*这样的事情。

#include <stdio.h> 
#include <stdlib.h> 
#include <ctype.h> 

yylex() { 
     int c; 
     char *p, buf[1000]; 

     for(c = get(); isspace(c); c = get()); 

     if(isdigit(c)) { 
       p = buf; 
       while(isdigit(c)) { 
         *p++ = c; 
         c = get(); 

       } 
       *p = 0; 
       if(c != '.') { 
         unget(c); 
         int i = atoi(buf); 
         return INT; 
       } 
       assert(c == '.'); 
       *p++ = c; 
       c = get(); 
       while(isdigit(c)) { 
         *p++ = c; 
         c = get(); 
       } 
       *p = 0; 
       float f = atof(buf); 
       unget(c); 
       return DECIMAL; 
     } 
} 

还有很多细节还没有说明。注意EOF。缓冲区溢出。将yylval设置为int或float。解析简单数字以外的令牌。

+0

快速打字 - 输入明文答案花了我更长的时间。 :)我通常把这种类型的代码放在一个函数中,然后当调用者遇到在当前当前上下文中启动一个数字的东西时,它会被调用。 – xxbbcc

+0

@xxbbc,你的回答比较好,也许一起会帮助OP。理论与实践。是的,小功能很好。 –

+0

@CharlieBurns - 我可能是错的,但不相信'get()'或'unget()'是为ANSI C定义的.OP已标记C. – ryyker