用C构建一个非常简单的解析器
我试图用C语言为一个类构建一个非常简单的解析器。它所要做的就是从输入文件中读取一个标志,确定该标志是在int、char还是float之前,然后将int/float/char写入相应的.txt文件。例如,I 9898将被打印到int.txt。无论何时使用讲师提供的测试脚本,我都会遇到以下错误: parser.c:1:1:错误:未知类型名称“e” parser.c:1:10:错误:应为“=”,“,”,“;”,”“打开”之前的asm或“属性” parser.c:1:10:错误:未知类型名称“on” 这是我的密码,请告诉我。非常感谢:用C构建一个非常简单的解析器,c,parsing,C,Parsing,我试图用C语言为一个类构建一个非常简单的解析器。它所要做的就是从输入文件中读取一个标志,确定该标志是在int、char还是float之前,然后将int/float/char写入相应的.txt文件。例如,I 9898将被打印到int.txt。无论何时使用讲师提供的测试脚本,我都会遇到以下错误: parser.c:1:1:错误:未知类型名称“e” parser.c:1:10:错误:应为“=”,“,”,“;”,”“打开”之前的asm或“属性” parser.c:1:10:错误:未知类型名称“on” 这
int main(int argc, char *argv[])
{
#include <stdio.h>
FILE *input = fopen("input.txt", "r");
FILE *ints.txt = fopen("ints.txt" "w");
FILE *chars.txt = fopen("chars.txt", "w");
FILE *floats.txt = fopen("floats.txt", "w");
char flag;
int ipint;
char ipchar;
float ipfloat;
int exitStatus = fscanf(input.txt, "%c", &flag);
while (exitStatus != EOF)
{
if (flag == I)
{
fscanf(input.txt, "%i", &ipint);
fprintf(ints.txt, ipint);
}
if (flag == C)
{
fscanf(input.txt, "%c", &ipchar);
fprintf(chars.txt, ipchar);
}
if (flag == F)
{
fscanf(input.txt, "%f", &ipfloat);
fprintf(floats.txt, ipfloat);
}
}
fclose(input.txt);
fclose(ints.txt);
fclose(floats.txt);
fclose(chars.txt);
}
将标准头放在文件范围,而不是块范围:
#include <stdio.h>
int main(int argc, char *argv[])
{
...
将标准头放在文件范围,而不是块范围:
#include <stdio.h>
int main(int argc, char *argv[])
{
...
使用switch语句,而不是多个if语句
fprintf与printf相同,唯一的区别是您可以决定标准输出,所以仍然需要字符格式
变量名不能有空。字符,因为这是为访问对象的成员而保留的
exitStatus需要在每次迭代时更新,以便程序知道何时停止读取文件。我用了fgetc和ungetc
此代码应满足您的需要:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *input = fopen("input.txt", "r");
FILE *ints = fopen("ints.txt", "w+");
FILE *chars = fopen("chars.txt", "w+");
FILE *floats = fopen("floats.txt", "w+");
int flag, ipint, exitStatus;
char ipchar;
float ipfloat;
if (NULL == input) {
perror("File not found [input.txt]");
return EXIT_FAILURE;
}
while ((exitStatus = fgetc(input)) != EOF && ungetc(exitStatus, input))
{
fscanf(input, "%d", &flag);
switch (flag) {
case 'I':
fscanf(input, "%i", &ipint);
fprintf(ints, "%i", ipint);
break;
case 'C':
fscanf(input, "%c", &ipchar);
fprintf(chars, "%c", ipchar);
break;
case 'F':
fscanf(input, "%f", &ipfloat);
fprintf(floats, "%f", ipfloat);
break;
default:
puts("Flag not recognized");
fclose(input);
fclose(ints);
fclose(floats);
fclose(chars);
return EXIT_FAILURE;
}
}
fclose(input);
fclose(ints);
fclose(floats);
fclose(chars);
return EXIT_SUCCESS;
}
使用switch语句,而不是多个if语句
fprintf与printf相同,唯一的区别是您可以决定标准输出,所以仍然需要字符格式
变量名不能有空。字符,因为这是为访问对象的成员而保留的
exitStatus需要在每次迭代时更新,以便程序知道何时停止读取文件。我用了fgetc和ungetc
此代码应满足您的需要:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *input = fopen("input.txt", "r");
FILE *ints = fopen("ints.txt", "w+");
FILE *chars = fopen("chars.txt", "w+");
FILE *floats = fopen("floats.txt", "w+");
int flag, ipint, exitStatus;
char ipchar;
float ipfloat;
if (NULL == input) {
perror("File not found [input.txt]");
return EXIT_FAILURE;
}
while ((exitStatus = fgetc(input)) != EOF && ungetc(exitStatus, input))
{
fscanf(input, "%d", &flag);
switch (flag) {
case 'I':
fscanf(input, "%i", &ipint);
fprintf(ints, "%i", ipint);
break;
case 'C':
fscanf(input, "%c", &ipchar);
fprintf(chars, "%c", ipchar);
break;
case 'F':
fscanf(input, "%f", &ipfloat);
fprintf(floats, "%f", ipfloat);
break;
default:
puts("Flag not recognized");
fclose(input);
fclose(ints);
fclose(floats);
fclose(chars);
return EXIT_FAILURE;
}
}
fclose(input);
fclose(ints);
fclose(floats);
fclose(chars);
return EXIT_SUCCESS;
}
建议的修改:
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE fp_input = NULL;
FILE fp_ints = NULL;
FILE fp_chars = NULL;
FILE fp_floats = NULL;
char flag;
int ipint;
char ipchar;
float ipfloat;
int exitStatus;
if (!(fp_input= fopen("input.txt", "r")) {
perror ("fp_input failed");
return 1;
}
if (!(fp_ints = fopen("ints.txt" "w")) {
...
if (fscanf(fp_input, "%c", &flag)!= 1) {
...
while (exitStatus != EOF){
switch (flag) {
case 'I' :
fscanf(fp_input,"%i",&ipint);
fprintf(fp_ints, "%d", ipint);
break;
case 'C' :
...
default :
...
}
换言之:
1包含项位于错误的位置
2我不会使用像input.txt这样的变量名,在名称中加句点
我想你指的是常数‘I’,而不是变量I
4您应尽可能随时检查错误,如fopen、fscanf等
5您需要fprintf的格式字符串建议的更改:
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE fp_input = NULL;
FILE fp_ints = NULL;
FILE fp_chars = NULL;
FILE fp_floats = NULL;
char flag;
int ipint;
char ipchar;
float ipfloat;
int exitStatus;
if (!(fp_input= fopen("input.txt", "r")) {
perror ("fp_input failed");
return 1;
}
if (!(fp_ints = fopen("ints.txt" "w")) {
...
if (fscanf(fp_input, "%c", &flag)!= 1) {
...
while (exitStatus != EOF){
switch (flag) {
case 'I' :
fscanf(fp_input,"%i",&ipint);
fprintf(fp_ints, "%d", ipint);
break;
case 'C' :
...
default :
...
}
换言之:
1包含项位于错误的位置
2我不会使用像input.txt这样的变量名,在名称中加句点
我想你指的是常数‘I’,而不是变量I
4您应尽可能随时检查错误,如fopen、fscanf等
5您的fprintf需要一个格式字符串include属于文件的开头,而不是main中。还有一个提醒:常规变量名不能有一个。在他们里面。在C中,I、F和C将被视为未声明的变量名。代码中还有其他几个问题,fopen可能会失败,您需要检查返回代码。你需要在引号之间加上字符,比如:ifflag=='I',变量名中也禁止有点,这是无效的:FILE*ints.txt。不要用C写解析器。这已经完成了,你可以做得更好的可能性很小。相反,看看lex和yacc,从标记和语法生成解析器。@AndreasGrapentin-他说这是为了类赋值,所以我怀疑他是否有语言选择。include属于文件的开头,而不是main内部。还有一个提醒:常规变量名不能有一个。在他们里面。在C中,I、F和C将被视为未声明的变量名。代码中还有其他几个问题,fopen可能会失败,您需要检查返回代码。你需要在引号之间加上字符,比如:ifflag=='I',变量名中也禁止有点,这是无效的:FILE*ints.txt。不要用C写解析器。这已经完成了,你可以做得更好的可能性很小。相反,看看lex和yacc,从标记和语法生成解析器。@AndreasGrapentin-他说这是一个类赋值,所以我怀疑他是否有语言选择。太棒了,谢谢。除了fopen和上面的评论之外,还有什么值得你关注的吗?太棒了,谢谢。除了fopen和上面的评论之外,还有什么值得你关注的吗?非常感谢,我的if语句有什么问题吗?或者开关是否工作得更好?因为如果我的if没有问题,我想保留它们,我们还没有学习switch语句。是的,if语句没有问题。这只是一个我推荐切换的偏好问题。我喜欢使用switch-case语句,因为它们看起来更具可读性,而程序看起来更少clustered@Smac89:程序中存在错误,如果标志无效,则不关闭文件。另外,从main返回-1不是标准的,您应该返回EXIT_FAILURE,对于posix系统,它是1。@Smac89 switch case比if快一点,因为switch case可以直接编译为jmp指令,但if可能不会。非常感谢,我的if语句或does switch有什么问题吗
只是工作得更好?因为如果我的if没有问题,我想保留它们,我们还没有学习switch语句。是的,if语句没有问题。这只是一个我推荐切换的偏好问题。我喜欢使用switch-case语句,因为它们看起来更具可读性,而程序看起来更少clustered@Smac89:程序中存在错误,如果标志无效,则不关闭文件。另外,从main返回-1也不是标准的,您应该返回EXIT_FAILURE,对于posix系统为1。@Smac89开关大小写比if快一点,因为开关大小写可以直接编译为jmp指令,但if可能不会。