用 C 语言构建基本符号表

发布于 2025-01-09 12:39:06 字数 3953 浏览 0 评论 0原文

我目前正在使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

趁年轻赶紧闹 2025-01-16 12:39:06

...我认为我们通常不愿意参与人们的课程作业,但内特,你似乎已经考虑过这个问题一段时间了。

我不太明白你的导师的建议。我在您的代码中没有看到 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!

始于初秋 2025-01-16 12:39:06

有很多问题。这甚至无法编译:

  1. read与系统调用冲突(即重命名它)
  2. read具有UB(未定义行为),因为它启动了fortable 数组末尾处循环
  3. 符号打印代码在各处复制。最好定义一个表打印函数(例如tblprint)和一个符号打印函数(例如symprint)。
  4. 用于打印符号的格式使用(错误地)可变精度格式说明符(例如,%*s 需要两个 参数:int len,char *str 使用 -Wall 作为编译选项,这些语句会被标记。
  5. AFAICT,普通格式说明符工作正常。
  6. if (sym->name == NULL)永远有效,因为它是一个固定长度数组。我们需要使用char *
  7. 使用 i 作为数组 count 的全局变量是有误导性的。尝试更具描述性的内容(例如) tabcount
  8. 在任何地方使用 table[i].whatever 很麻烦。尝试使用指针(例如sym->whatever
  9. initialize [以及其他一些]需要一个return一个值。

我使用 cpp 条件来表示旧代码与新代码:

#if 0
// old code
#else
// new code
#endif

这是重构的代码。是有注释的。它编译干净并通过了基本测试:

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

struct ADT {
// NOTE/BUG: the if (sym->name == NULL) will fail
#if 0
    char name[18];                      // lexeme name
#else
    const char *name;                   // lexeme name
#endif
    char usage;

    // I is integer, S is type string, I for identifier
    char type;

    // scope of where it was declared, inserted for later use
    int scope;
    int reference;
};

#if 0
typedef struct ADT new_type;
new_type table[200];
#else
typedef struct ADT ADT;
ADT table[200];
#endif

int tabcount = 0;

// NOTE/BUG: "read" conflicts with a syscall name
#if 0
//Read function to read input and check for duplicates
int
read(char *name, char usage, char type, char scope)
#else
// find_entry -- find a matching entry (if it exists)
int
find_entry(char *name, char usage, char type, char scope)
#endif
{

// NOTE/BUG: this is UB (undefined behavior) because you're starting at one
// past the end of the array
#if 0
    for (int j = sizeof(table) / sizeof(table[0]); j >= 0; --j) {
#else
    for (int j = tabcount - 1; j >= 0; --j) {
#endif
        ADT *sym = &table[j];
        if (strcmp(sym->name, name) == 0 &&
            sym->usage == usage &&
            sym->type == type &&
            sym->scope == scope)
            return 1;
    }

    // not found! that's good
    return -1;
}

//Create function to insert new input into symbol table
int
create(char *name, char usage, char type, char scope)
{
    ADT *sym = &table[tabcount];

// NOTE/BUG: this needs to be a pointer to a string to allow long strings and
// for "if (sym->name == NULL)" to be valid
#if 0
    strcpy(sym->name, name);
#else
    sym->name = strdup(name);
#endif
    sym->usage = usage;
    sym->type = type;
    sym->scope = scope;
    if (sym->usage == 'I' && sym->type == 'L')
        sym->reference = atoi(name);
    else
        sym->reference = -1;

    return tabcount++;
}

// Function to initialize the symbol table and clear it. also creates the fred
// lexeme
int
initialize(char *name, char usage, char type, char scope)
{

    create("Fred", 'I', 'I', '0');

    return 0;
}

void
symprint(ADT *sym)
{
    int j = sym - table;

// NOTE/BUG: with (e.g) %*d this is variable precision field -- it requires
// _two_ arguments: <int wid>,<int val>
#if 0
    printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n",
        j, sym->name, sym->scope, sym->type,
        sym->usage, sym->reference);
#else
    printf("%d\t\t%s\t%d\t%c\t%c\t%d\n",
        j, sym->name, sym->scope, sym->type,
        sym->usage, sym->reference);
#endif
}

void
tblprint(int title)
{

    if (title)
        printf("#\t\tName\tScope\tType\tUsage\tReference\n");

    for (int j = 0; j < tabcount; j++) {
        ADT *sym = &table[j];
        if (sym->name == NULL)
            break;
        symprint(sym);
    }
}

// Print function to print the symbol table
int
print(char *name, char usage, char type, char scope)
{

    printf("Nate's Symbol Table\n");
    tblprint(1);

    return 0;
}

// Main function to take input and produce the symbol table lexemes
int
main()
{
    printf("Course: CSCI 490 Name: Nathaniel Bennett NN: 02 Assignment: A03\n");
    printf("\n");
    create("Fred", 'I', 'I', 0);

    tblprint(1);

    // keep asking for a lexeme until we type STOP or stop

    while (1) {
        char lexeme[256];
        char nUsage;
        char nType;
        char nScope;

        // enter lexeme name
        printf("Enter a lexeme: \n");
        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);

        tblprint(0);
    }

    printf("Nate's Symbol Table\n");
    tblprint(1);

    return 0;
}

There are a number of issues. This won't even compile:

  1. read conflicts with the syscall (i.e. rename it)
  2. read has UB (undefined behavior) because it starts the for loop at one beyond the end of the table array
  3. The symbol printing code is replicated everywhere. Better to define a table printing function (e.g. tblprint) and a symbol printing function (e.g. symprint).
  4. The format used to print a symbol uses (incorrectly) variable precision format specifiers (e.g.) %*s expects two arguments: int len,char *str With -Wall as a compile option, these statements are flagged.
  5. AFAICT, ordinary format specifiers work fine.
  6. The if (sym->name == NULL) will never be valid because it is a fixed length array. We need to use a char *.
  7. Using i as a global for the count of the array is misleading. Try something more descriptive (e.g.) tabcount
  8. Using table[i].whatever everywhere is cumbersome. Try using a pointer (e.g. sym->whatever)
  9. initialize [and some others] need a return with a value.

I've used cpp conditionals to denote old code vs new code:

#if 0
// old code
#else
// new code
#endif

Here is the refactored code. It is annotated. It compiles cleanly and passes a rudimentary test:

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

struct ADT {
// NOTE/BUG: the if (sym->name == NULL) will fail
#if 0
    char name[18];                      // lexeme name
#else
    const char *name;                   // lexeme name
#endif
    char usage;

    // I is integer, S is type string, I for identifier
    char type;

    // scope of where it was declared, inserted for later use
    int scope;
    int reference;
};

#if 0
typedef struct ADT new_type;
new_type table[200];
#else
typedef struct ADT ADT;
ADT table[200];
#endif

int tabcount = 0;

// NOTE/BUG: "read" conflicts with a syscall name
#if 0
//Read function to read input and check for duplicates
int
read(char *name, char usage, char type, char scope)
#else
// find_entry -- find a matching entry (if it exists)
int
find_entry(char *name, char usage, char type, char scope)
#endif
{

// NOTE/BUG: this is UB (undefined behavior) because you're starting at one
// past the end of the array
#if 0
    for (int j = sizeof(table) / sizeof(table[0]); j >= 0; --j) {
#else
    for (int j = tabcount - 1; j >= 0; --j) {
#endif
        ADT *sym = &table[j];
        if (strcmp(sym->name, name) == 0 &&
            sym->usage == usage &&
            sym->type == type &&
            sym->scope == scope)
            return 1;
    }

    // not found! that's good
    return -1;
}

//Create function to insert new input into symbol table
int
create(char *name, char usage, char type, char scope)
{
    ADT *sym = &table[tabcount];

// NOTE/BUG: this needs to be a pointer to a string to allow long strings and
// for "if (sym->name == NULL)" to be valid
#if 0
    strcpy(sym->name, name);
#else
    sym->name = strdup(name);
#endif
    sym->usage = usage;
    sym->type = type;
    sym->scope = scope;
    if (sym->usage == 'I' && sym->type == 'L')
        sym->reference = atoi(name);
    else
        sym->reference = -1;

    return tabcount++;
}

// Function to initialize the symbol table and clear it. also creates the fred
// lexeme
int
initialize(char *name, char usage, char type, char scope)
{

    create("Fred", 'I', 'I', '0');

    return 0;
}

void
symprint(ADT *sym)
{
    int j = sym - table;

// NOTE/BUG: with (e.g) %*d this is variable precision field -- it requires
// _two_ arguments: <int wid>,<int val>
#if 0
    printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n",
        j, sym->name, sym->scope, sym->type,
        sym->usage, sym->reference);
#else
    printf("%d\t\t%s\t%d\t%c\t%c\t%d\n",
        j, sym->name, sym->scope, sym->type,
        sym->usage, sym->reference);
#endif
}

void
tblprint(int title)
{

    if (title)
        printf("#\t\tName\tScope\tType\tUsage\tReference\n");

    for (int j = 0; j < tabcount; j++) {
        ADT *sym = &table[j];
        if (sym->name == NULL)
            break;
        symprint(sym);
    }
}

// Print function to print the symbol table
int
print(char *name, char usage, char type, char scope)
{

    printf("Nate's Symbol Table\n");
    tblprint(1);

    return 0;
}

// Main function to take input and produce the symbol table lexemes
int
main()
{
    printf("Course: CSCI 490 Name: Nathaniel Bennett NN: 02 Assignment: A03\n");
    printf("\n");
    create("Fred", 'I', 'I', 0);

    tblprint(1);

    // keep asking for a lexeme until we type STOP or stop

    while (1) {
        char lexeme[256];
        char nUsage;
        char nType;
        char nScope;

        // enter lexeme name
        printf("Enter a lexeme: \n");
        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);

        tblprint(0);
    }

    printf("Nate's Symbol Table\n");
    tblprint(1);

    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文