Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C词法分析器。使用开关分析和计数小数/非小数_C_Switch Statement_Case_Analyzer_Lexical - Fatal编程技术网

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

C词法分析器。使用开关分析和计数小数/非小数,c,switch-statement,case,analyzer,lexical,C,Switch Statement,Case,Analyzer,Lexical,我的词法分析器可以识别数字(5555543667)、小数(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) {

我的词法分析器可以识别数字(5555543667)、小数(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;

尝试了很多事情,但我被正式卡住了

您真的应该使用这种练习,而不是长开关语句。您的代码将简单得多,根本不必使用
goto

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

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

  • 数字可以(可选)以
    +
    -
    开头(如果您支持签名数字)
  • 它可能有0..n个数字
  • 如果以下字符不是小数点符号,则应为分隔符,否则为无效符号。如果是分隔符,则您的号码终止
  • 小数点后应为1..n位
  • 当到达输入的末尾或遇到分隔符时,数字将终止
所有这些都可以在几行代码中完成——只要有一个指向当前输入字符的指针,然后一个接一个地向前走,检查每个字符,并根据字符类决定要做什么


现在,这种特殊的方法不使用科学记数法等来处理浮点数。但是,一旦你完成了基本操作,添加这些附加值就非常简单。

使用像
digit\u follow\u peroid
这样的变量来保持状态。每次遇到peroid时,将变量设置为false,然后在decimal开关块中遇到数字时,将其设置为true。在
strncpy
之前,检查变量值以确定t.length。也许你还需要其他变量来配合它。最好的方法是定义一个状态转移矩阵,它比gotos好得多。

我认为这是对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;
        }
}
#包括
#包括
#包括
yylex(){
INTC;
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;
如果(c!='。){
unget(c);
int i=原子(buf);
返回INT;
}
断言(c='.');
*p++=c;
c=get();
while(isdigit(c)){
*p++=c;
c=get();
}
*p=0;
浮点数f=atof(buf);
unget(c);
返回小数;
}
}

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

词法分析不是一个需要大量goto的地方。考虑一些for循环和isdigit()调用。goto是邪恶的,尽量不要习惯它们。至于这个问题,你的问题是,在处理完整个项目之前,你不知道这个案例。您需要首先将字符串分解为“单词”,然后再逐个处理它们,将每个单词作为一个整体(而不是一个字符一个字符地处理)。使用flex不是更容易吗?如果这是一个学习练习,你学到了什么?快速键入-我花了更长的时间键入纯文本答案。:)我通常把这类代码放在函数中,当调用者遇到在当前上下文中以数字开头的东西时,就会调用它。@xxbbc,你的答案更好,也许结合起来对操作理论和实践会有帮助。是的,小功能很好。@Ryker,我粗略地说。get()和unget()是返回下一个字符或将其推回的通用函数。可能来自文件,可能来自缓冲区。莱克斯提供了他们,我模仿了那个界面。
#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;
        }
}