用 C 语言构建基本符号表
我目前正在使用 C 语言构建一个符号表程序。它需要尽可能简单,同时具有所需的功能,因为我预计将在本学期结束时生成一个工作编译器。我目前有一个有效的实现,可以根据用户输入创建符号表条目,但它并不是 100% 需要的位置。我只需要根据教授给我的反馈提供一些指导。我知道有些事情我需要改变,我是 C 编码新手,我也想同时学习 Python 和 R,所以我有点不知所措。我知道我需要一个单独的初始化和打印函数,创建函数中不应该有输入或输出,并且每个条目的范围为 0。我陷入困境的是创建用于初始化和打印的函数,而不需要失去我已经拥有的当前功能。任何帮助表示赞赏。这是我当前的代码实现:
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
struct ADT {
char name[18]; // lexeme name
char usage;
char type; // I is integer, S is type string, I for identifier
int scope; // scope of where it was declared, inserted for later use
int reference;
};
typedef struct ADT new_type;
new_type table[200];
int i = 0;
int read(char *name, char usage, char type, char scope) { //Read function to read input and check for duplicates
for (int j = sizeof(table) / sizeof(table[0]); j >= 0; --j) {
if (strcmp(table[j].name, name) == 0 &&
table[j].usage == usage &&
table[j].type == type &&
table[j].scope == scope)
return 1; // found
}
return -1; // not found! that's good
}
int create( char *name, char usage, char type, char scope) { //Create function to insert new input into symbol table
strcpy(table[i].name, name);
table[i].usage = usage;
table[i].type = type;
table[i].scope = scope;
if (table[i].usage == 'I' && table[i].type == 'L')
table[i].reference = atoi(name);
else
table[i].reference = -1;
return i++;
}
int initialize(char *name, char usage, char type, char scope) { // Function to initialize the symbol table and clear it. also creates the fred lexeme
create("Fred", 'I', 'I', '0');
}
int print(char *name, char usage, char type, char scope) { // Print function to print the symbol table
printf("Nate's Symbol Table\n");
printf("#\t\tName\tScope\tType\tUsage\tReference\n");
for (int j = 0; j < i; j++) {
if (table[j].name == NULL)
break;
printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n", j, table[j].name, table[j].scope, table[j].type, table[j].usage, table[j].reference);
}
}
int main() { // Main function to take input and produce the symbol table lexemes
printf("Course: CSCI 490 Name: Nathaniel Bennett NN: 02 Assignment: A03\n");
printf("\n");
create("Fred", 'I', 'I', 0);
for (int j = 0; j < i; j++) {
if (table[j].name == NULL)
break;
printf("#\t\tName\tScope\tType\tUsage\tReference\n");
printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n", j, table[j].name, table[j].scope, table[j].type, table[j].usage, table[j].reference);
}
// keep asking for a lexeme until we type STOP or stop
while (1) {
char lexeme[256];
char nUsage;
char nType;
char nScope;
printf("Enter a lexeme: \n"); //enter lexeme name
scanf("%s", lexeme);
if (strcmp(lexeme, "stop") == 0) break;
printf("Enter its usage: \n");
scanf(" %c", &nUsage);
printf("Enter its type: \n");
scanf(" %c", &nType);
printf("Enter its scope: \n");
scanf(" %c", &nScope);
printf("%s, %c, %c, %c\n", lexeme, nUsage, nType, nScope);
create(lexeme, nUsage, nType, nScope);
for (int j = 0; j < i; j++) {
if (table[j].name == NULL)
break;
printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n", j, table[j].name, table[j].scope, table[j].type, table[j].usage, table[j].reference);
}
}
printf("Nate's Symbol Table\n");
printf("#\t\tName\tScope\tType\tUsage\tReference\n");
for (int j = 0; j < i; j++) {
if (table[j].name == NULL)
break;
printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n", j, table[j].name, table[j].scope, table[j].type, table[j].usage, table[j].reference);
}
return 0;
}```
I am currently building a symbol table program using C. It needs to stay as simple as possible while having the required functionality as I am expected to produce a working compiler by the end of the semester. I currently have a working implementation that creates entries into the symbol table from user input but it is not 100% where it needs to be. I just need some guidance based on the feedback I was given from my professor. I understand that there are some things I need to change, I am new to coding in C and I am also trying to learn Python and R at the same time so im a little overwhelmed. I know I need a separate initialize and print function, That there should be no Input or Output in the create function, and that every entry has a scope of 0. where I'm stuck at, is creating the functions for initialize and print without losing the current functionality that I already have. Any help is appreciated. Here is my current implementation of the code:
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
struct ADT {
char name[18]; // lexeme name
char usage;
char type; // I is integer, S is type string, I for identifier
int scope; // scope of where it was declared, inserted for later use
int reference;
};
typedef struct ADT new_type;
new_type table[200];
int i = 0;
int read(char *name, char usage, char type, char scope) { //Read function to read input and check for duplicates
for (int j = sizeof(table) / sizeof(table[0]); j >= 0; --j) {
if (strcmp(table[j].name, name) == 0 &&
table[j].usage == usage &&
table[j].type == type &&
table[j].scope == scope)
return 1; // found
}
return -1; // not found! that's good
}
int create( char *name, char usage, char type, char scope) { //Create function to insert new input into symbol table
strcpy(table[i].name, name);
table[i].usage = usage;
table[i].type = type;
table[i].scope = scope;
if (table[i].usage == 'I' && table[i].type == 'L')
table[i].reference = atoi(name);
else
table[i].reference = -1;
return i++;
}
int initialize(char *name, char usage, char type, char scope) { // Function to initialize the symbol table and clear it. also creates the fred lexeme
create("Fred", 'I', 'I', '0');
}
int print(char *name, char usage, char type, char scope) { // Print function to print the symbol table
printf("Nate's Symbol Table\n");
printf("#\t\tName\tScope\tType\tUsage\tReference\n");
for (int j = 0; j < i; j++) {
if (table[j].name == NULL)
break;
printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n", j, table[j].name, table[j].scope, table[j].type, table[j].usage, table[j].reference);
}
}
int main() { // Main function to take input and produce the symbol table lexemes
printf("Course: CSCI 490 Name: Nathaniel Bennett NN: 02 Assignment: A03\n");
printf("\n");
create("Fred", 'I', 'I', 0);
for (int j = 0; j < i; j++) {
if (table[j].name == NULL)
break;
printf("#\t\tName\tScope\tType\tUsage\tReference\n");
printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n", j, table[j].name, table[j].scope, table[j].type, table[j].usage, table[j].reference);
}
// keep asking for a lexeme until we type STOP or stop
while (1) {
char lexeme[256];
char nUsage;
char nType;
char nScope;
printf("Enter a lexeme: \n"); //enter lexeme name
scanf("%s", lexeme);
if (strcmp(lexeme, "stop") == 0) break;
printf("Enter its usage: \n");
scanf(" %c", &nUsage);
printf("Enter its type: \n");
scanf(" %c", &nType);
printf("Enter its scope: \n");
scanf(" %c", &nScope);
printf("%s, %c, %c, %c\n", lexeme, nUsage, nType, nScope);
create(lexeme, nUsage, nType, nScope);
for (int j = 0; j < i; j++) {
if (table[j].name == NULL)
break;
printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n", j, table[j].name, table[j].scope, table[j].type, table[j].usage, table[j].reference);
}
}
printf("Nate's Symbol Table\n");
printf("#\t\tName\tScope\tType\tUsage\tReference\n");
for (int j = 0; j < i; j++) {
if (table[j].name == NULL)
break;
printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n", j, table[j].name, table[j].scope, table[j].type, table[j].usage, table[j].reference);
}
return 0;
}```
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
...我认为我们通常不愿意参与人们的课程作业,但内特,你似乎已经考虑过这个问题一段时间了。
我不太明白你的导师的建议。我在您的代码中没有看到 create() 函数的 I/O。除非在他们看来对 strcpy() 的调用被视为 I/O。
不过,我确实看到你的 print() 函数有一些改进的空间。您的函数依赖于一个全局实体(表),然后它将您的循环与一个虚值(循环初始化中的“i”是什么?)以及您的逻辑有效询问的条件联系起来,“我是否用完了表” ?”
选择一个条件或另一个条件。简单地打印表格中找到的所有内容,在语义上是优雅的。如果传递对表的引用而不是对静态全局值的存在进行编码,则可以使该函数变得更好。因此,与其将所有这些值传递给 print() 函数,不如只传递一个参数呢?传递对表的引用,然后您的函数可以用于其他类似的转储操作。它变得更加普遍,这是一件好事。
我也想说这个。我更喜欢使用 sprintf() 将输出暂存在字符串中,然后当一切准备就绪时,我一次性输出所有内容。这更容易检查和调试。
另外,我想这与你的作业无关,但每次使用 scanf() 时都要格外警惕——每当我有一个坏指针时,它通常是我的第一嫌疑人。
一定要尝试隔离或消除对像这样的混沌函数的调用。
不断思考如何让你的功能变得更强,不断重构。你会做得很棒!
...I think we're normally reluctant to get up in people's course assignments, but you seem like you have thought about this for a while Nate.
I can't quite make out what your instructor is suggesting. I do not see I/O in your code for the create() function. Unless the call to strcpy() is considered I/O in their view.
I do see some room for improvement in your print() function though. Your function relies upon a global entity (table) and then it ties your loop both to an imaginary value (what is "i" in your loop initialization?) AND to a condition where your logic asks effectively, "did I run out of table?"
Choose one condition or the other. There is a semantic elegance in simply printing everything you find in the table. You can make the function better if you pass a reference to the table rather than code to the existence of a static global value. So instead of passing all those values to your print() function, how about just one argument? Pass a reference to table, and your function could then be used for other similar dump operations. It becomes more generalized, and that's a good thing.
I would also say this. I prefer using sprintf() to stage my output in a string and then when everything is ready, I output it all at one time. This is easier to inspect and debug.
Also, not related to your assignment I imagine, but be extra-vigilant every time you use scanf() -- it was often my number one suspect whenever I had a bad pointer.
Definitely try to isolate or eliminate calls to chaotic functions like that one.
Keep thinking about how to make your function stronger, keep refactoring. You'll do great!
有很多问题。这甚至无法编译:
read
与系统调用冲突(即重命名它)read
具有UB(未定义行为),因为它启动了for
在table
数组末尾处循环tblprint
)和一个符号打印函数(例如symprint
)。%*s
需要两个 参数:int len,char *str 使用
-Wall
作为编译选项,这些语句会被标记。if (sym->name == NULL)
将永远有效,因为它是一个固定长度数组。我们需要使用char *
。i
作为数组 count 的全局变量是有误导性的。尝试更具描述性的内容(例如)tabcount
table[i].whatever
很麻烦。尝试使用指针(例如sym->whatever
)initialize
[以及其他一些]需要一个return
一个值。我使用
cpp
条件来表示旧代码与新代码:这是重构的代码。是有注释的。它编译干净并通过了基本测试:
There are a number of issues. This won't even compile:
read
conflicts with the syscall (i.e. rename it)read
has UB (undefined behavior) because it starts thefor
loop at one beyond the end of thetable
arraytblprint
) and a symbol printing function (e.g.symprint
).%*s
expects two arguments:int len,char *str
With-Wall
as a compile option, these statements are flagged.if (sym->name == NULL)
will never be valid because it is a fixed length array. We need to use achar *
.i
as a global for the count of the array is misleading. Try something more descriptive (e.g.)tabcount
table[i].whatever
everywhere is cumbersome. Try using a pointer (e.g.sym->whatever
)initialize
[and some others] need areturn
with a value.I've used
cpp
conditionals to denote old code vs new code:Here is the refactored code. It is annotated. It compiles cleanly and passes a rudimentary test: