繁体   English   中英

Lexical Analyzer C程序,用于识别令牌

[英]Lexical Analyzer C program for identifying tokens

我写了一个用于lex分析器的C程序(一个小代码),它将识别关键字,标识符和常量。 我正在获取一个字符串(C源代码为字符串),然后将其拆分为单词。

#include <stdio.h>
#include <conio.h>
#include <string.h>

char symTable[5][7] = { "int", "void", "float", "char", "string" };

int main() {
    int i, j, k = 0, flag = 0;
    char string[7];
    char str[] = "int main(){printf(\"Hello\");return 0;}";
    char *ptr;
    printf("Splitting string \"%s\" into tokens:\n", str);
    ptr = strtok(str, " (){};""");
    printf("\n\n");
    while (ptr != NULL) {
        printf ("%s\n", ptr);

        for (i = k; i < 5; i++) {
            memset(&string[0], 0, sizeof(string));
            for (j = 0; j < 7; j++) {
                string[j] = symTable[i][j];
            }

            if (strcmp(ptr, string) == 0) {
                printf("Keyword\n\n");
                break;
            } else
            if (string[j] == 0 || string[j] == 1 || string[j] == 2 ||
                string[j] == 3 || string[j] == 4 || string[j] == 5 ||
                string[j] == 6 || string[j] == 7 || string[j] == 8 ||
                string[j] == 9) {
                printf("Constant\n\n");
                break;
            } else {
                printf("Identifier\n\n");
                break;
            }
        }
        ptr = strtok(NULL, " (){};""");
        k++;
    }
    _getch();
    return 0;
}

使用上面的代码,我可以识别关键字和标识符,但无法获得数字的结果。 我试过使用strspn()但无济于事。 我什至将0,1,2...,9替换为'0','1',....,'9'

任何帮助,将不胜感激。

这是您的解析器中的一些问题:

  • 测试string[j] == 0不会测试string[j]是否为数字0 数字字符写为'0''9' ,其值在ASCII和UTF-8中为48至57。 此外,您应该比较*p而不是string[j]以测试string[j]是否有数字表示数字的开头。

  • strtok()分割字符串不是一个好主意:它修改字符串并用'\\0'覆盖第一个分隔符:这将防止匹配运算符,例如() ...

  • 字符串" (){};"""" (){};"完全相同 为了转义"内部字符串,您必须使用\\"

要为C编写词法分析器,您应该打开第一个字符并根据第一个字符的值检查以下字符:

  • 如果您有空格,请跳过它
  • 如果有// ,则为行注释:跳过所有字符,直到换行符。
  • 如果有/* ,则它是一个块注释:跳过所有字符,直到获得对*/
  • 如果您有一个' ,则您有一个字符常量:解析字符,处理转义序列,直到获得结束'
  • 如果您有一个" ,则您有一个字符串文字。其作用与字符常量相同。
  • 如果您有一个数字,消耗掉所有后续数字,那么您就有一个整数。 解析整数语法需要更多代码:将其留待以后使用。
  • 如果您有字母或下划线:使用所有后续字母,数字和下划线,然后将该单词与一组预定义的关键字进行比较。 您有一个关键字或一个标识符。
  • 否则,您有一个运算符:检查下一个字符是否是2或3个字符运算符的一部分,例如==>>=

这就是一个简单的C解析器。 完整的语法需要更多的工作,但是您一次只能到达一个步骤。

在编写lexer时,请始终创建用于查找令牌的特定函数(名称yylex用于工具System Lex ,这就是我使用该名称的原因)。 用main编写词法分析器不是一个聪明的主意,尤其是如果您以后要进行语法和语义分析。

从您的问题尚不清楚,您是否只想弄清楚数字令牌是什么,还是要令牌+获取数字值。 我将假设第一个。

这是示例代码 ,可以找到整数:

int yylex(){

    /* We read one char from standard input */
    char c = getchar();

    /* If we read new line, we will return end of input token */
    if(c == '\n')
        return EOI;

    /* If we see digit on input, we can not return number token at the moment. 
         For example input could be 123a and that is lexical error  */
    if(isdigit(c)){

        while(isdigit(c = getchar()))
            ;

        ungetc(c,stdin);
        return NUM;
    }

    /* Additional code for keywords, identifiers, errors, etc. */
}

令牌EOINUM等应在顶部定义。 稍后,当您要编写语法分析时,可以使用这些标记来确定代码是否响应语言语法。 在词法分析中,通常根本没有定义ASCII值,例如,您的词法分析器函数将仅返回')' 知道这一点,令牌应定义为255值以上。 例如:

#define EOI 256
#define NUM 257

如果您还有其他疑问,请随时提问。

string[j]==1

该测试是错误的 (1) (在我听说过的所有C实现中),因为string[j]是一些char例如使用ASCII (或UTF-8 ,甚至是IBM大型机上使用的旧EBCDIC )编码和char digit 1不是数字1。在我的Linux / x86-64机器上(以及在大多数使用ASCII或UTF-8的机器上,例如几乎所有机器),使用UTF-8, 字符 1被编码为代码48(即(char)48 == '1'

你可能想要

string[j]=='1'

并且您应该考虑使用标准的isdigit (和相关)功能。

请注意,UTF-8实际上在任何地方都可以使用但是它是一种多字节编码(可显示字符)。 看到这个答案


注意(1): string[j]==1测试可能也放错了位置! 也许您可以在更好的地方测试isdigit(*ptr)

PS。 请养成使用所有警告和调试信息进行编译的习惯(例如,如果使用GCC,则使用gcc -Wall -Wextra -g ),并使用调试器 (例如gdb )。 您应该比在这里得到答案所花费的时间要短。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM