C词法分析器。使用开关来分析和计算小数/非小数

时间:2013-10-12 01:26:04

标签: c switch-statement case analyzer lexical

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

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

考虑一个包含以下内容的文本文件:555 2.3 55.23 44 5.

我的输出是

1 type 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;

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

3 个答案:

答案 0 :(得分:1)

你真的应该使用character classification functions这种练习而不是长切换语句。您的代码将更加简单,您根本不必使用goto

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

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

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

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

这一切都可以在少量代码行中完成 - 只需要一个指向当前输入字符的指针,然后逐个前进并检查每个字符并根据字符类决定做什么

现在,这种特殊方法不会使用科学记数法等来处理浮点数,但是一旦完成基本操作,添加额外内容就非常简单。

答案 1 :(得分: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。解析除简单数字之外的令牌。

答案 2 :(得分:0)

使用digit_follow_peroid之类的变量来保持状态。每次遇到peroid时,将变量设置为false,然后在十进制开关块中遇到一个数字时,将其设置为true。检查变量的值以确定strncpy之前的t.lengthbe。也许你还需要其他变量来与它一起工作。最好的方法是定义一个状态转换矩阵,它比gotos好得多。