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

时间:2016-07-13 06:01:28

标签: c lexical-analysis

我为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'

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:3)

以下是解析器中的一些问题:

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

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

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

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

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

关于简单的C解析器的问题。完整的语法需要更多的工作,但您将一次完成一步。

答案 1 :(得分:0)

当您编写词法分析器时,请始终创建找到您的令牌的特定功能(名称yylex用于工具 System Lex ,这就是我使用该名称的原因)。在main中编写lexer并不是一个聪明的主意,特别是如果你想稍后进行语法分析,语义分析。

根据您的问题,目前尚不清楚您是否只想弄清楚什么是数字标记,或者您是否需要标记+获取数字值。我将假设第一个。

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

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

如果您有任何进一步的问题,请随时提出。

答案 2 :(得分:0)

  

string[j]==1

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

你可能想要

string[j]=='1'

您应该考虑使用标准isdigit(及相关)功能。

请注意,UTF-8实际使用everywhere但是多字节编码(可显示字符)。请参阅此answer

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

PS。请养成使用所有警告和调试信息进行编译的习惯(例如,如果使用GCC,请使用gcc -Wall -Wextra -g ...)  并且使用调试器(例如gdb)。你应该在更短的时间内找到你的错误,而不是在这里得到答案。