0

我的词法分析器可以识别数字 (5,555,543667)、小数 (44.65,4.1) 和句点 (.)。

我可以很好地计算数字、小数和句点,但是当我遇到一个数字和句点彼此相邻时,它会将其计为小数。

考虑一个包含以下内容的文本文件: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;

尝试了多种方法,但我被正式卡住了。

4

3 回答 3

1

你真的应该为这种练习使用字符分类函数,而不是长的 switch 语句。您的代码会简单得多,而且您根本不必使用goto

例如,可以使用以下正则表达式来描述一个数字(添加空格以分解各个块):

[-+]? [0-9]* \.? [0-9]+

这已经显示了可能的状态转换:

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

所有这些都可以在几行代码中完成 - 只需有一个指向您当前输入字符的指针,然后一个接一个地向前推进并检查每个字符并根据字符类决定要做什么。

现在,这种特殊的方法不使用科学计数法等处理浮点数,但是一旦你完成了基础知识,添加额外的东西真的很简单。

于 2013-10-12T01:50:10.653 回答
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。解析简单数字以外的标记。

于 2013-10-12T01:54:13.500 回答
0

使用变量喜欢digit_follow_peroid保持状态。每次遇到 peroid 时,将变量设置为 false,然后当遇到十进制开关块中的数字时,将其设置为 true。检查变量的值以确定 t.lengthbefore strncpy。也许您还需要其他变量与它一起工作。最好的方法是定义一个状态转移矩阵,这比 goto 好很多。

于 2013-10-12T01:51:08.897 回答