C词法分析器。使用开关来分析和计算小数/非小数
我的词法分析器可识别数字(5,555,543667),小数(44.65,4.1)和句点(。)。C词法分析器。使用开关来分析和计算小数/非小数
我可以对数字,小数点和句点进行计数,但是当我遇到一个数字和句点相邻时,它会将其计为小数。
考虑包含一个文本文件: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;
尝试了多件事,但我被正式卡住了。
你真的应该使用character classification functions这种练习而不是长开关语句。你的代码会简单得多,你根本不需要使用goto
。
例如,数目可以用下面的正则表达式描述(加入的空白,打破了各种块):
此已经示出了可能的状态转移:
- 甲号码可以(可选)以
+
或-
(如果您支持带符号的数字)开头 - 它可能有0..n个数字
- 如果下列字符不是小数点符号,它应该是分隔符,否则它是无效符号。如果是分隔符,您的号码将被终止。
- 小数点后应该有1..1位数
- 当你到达输入的末尾或者你遇到一个分隔符
这一切都可以在线路屈指可数完成数量被终止的代码 - 只需要一个指向你当前输入字符的指针,然后一个接一个地前进,并检查每个字符并根据字符类别决定要做什么。
现在,这种特殊的方法并不使用科学记数法等处理浮点数,但是一旦完成基础知识后,添加额外的东西就非常简单。
使用像digit_follow_peroid
这样的变量来保持状态。每遇到一个循环时,将该变量设置为false,然后当您遇到小数点开关块中的一个数字时,将其设置为true。检查变量的值以确定t。长度在strncpy
之前。也许你还需要其他变量与它一起工作。最好的方法是定义一个状态转换矩阵,它比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;
}
}
还有很多细节还没有说明。注意EOF。缓冲区溢出。将yylval设置为int或float。解析简单数字以外的令牌。
词汇分析不是要求大量gotos的地方。考虑一些for循环和isdigit()调用。 –
gotos是邪恶的,尽量不要习惯于他们。至于这个问题,你的问题是,除非你处理完整个项目,否则你不知道这个案例。你需要首先将你的字符串分解成“单词”,后者逐个处理它们,每个单词作为一个整体(而不是逐个字符地处理)。 – SJuan76
使用flex会不会更容易?如果这是一个学习练习,你学到了什么? – rici