我为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'
。
任何帮助都将不胜感激。
答案 0 :(得分:3)
以下是解析器中的一些问题:
测试string[j] == 0
不会测试string[j]
是否为数字0
。数字的字符写为'0'
到'9'
,其值在ASCII和UTF-8中为48到57。此外,您应该比较*p
而不是string[j]
,以测试字符串中是否有数字表示数字的开头。
使用strtok()
拆分字符串不是一个好主意:它会修改字符串并使用'\0'
覆盖第一个分隔符字符:这将阻止匹配运算符例如(
,)
...
字符串" (){};"""
与" (){};"
完全相同。要在字符串内转义"
,您必须使用\"
。
要为C编写词法分析器,您应该打开第一个字符,并根据第一个字符的值检查以下字符:
//
,则为行注释:跳过换行符之前的所有字符。/*
,则为阻止评论:跳过所有字符,直到您获得对*/
。'
,则您有一个字符常量:解析字符,处理转义序列,直到您收到结束'
。"
,你就有astring文字。与字符常量相同。==
和>>=
。关于简单的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. */
}
应在顶部定义代币EOI
,NUM
等。稍后,当您要编写语法分析时,可以使用这些标记来确定代码是否响应语言语法。在词法分析中,通常根本不定义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
)。你应该在更短的时间内找到你的错误,而不是在这里得到答案。