[英]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编写词法分析器,您应该打开第一个字符并根据第一个字符的值检查以下字符:
//
,则为行注释:跳过所有字符,直到换行符。 /*
,则它是一个块注释:跳过所有字符,直到获得对*/
。 '
,则您有一个字符常量:解析字符,处理转义序列,直到获得结束'
。 "
,则您有一个字符串文字。其作用与字符常量相同。 ==
和>>=
。 这就是一个简单的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. */
}
令牌EOI
, NUM
等应在顶部定义。 稍后,当您要编写语法分析时,可以使用这些标记来确定代码是否响应语言语法。 在词法分析中,通常根本没有定义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.