简体   繁体   English

C语言-将输入转化为代码

[英]C language - turning input into code

Most of the times, the questions I ask have to do with a specific part of a code that i did incorrectly, or some bug that i overlooked, but this time, I don't know where to start. 大多数时候,我问的问题与我做错的代码的特定部分有关,或者与我忽略的一些错误有关,但是这次,我不知道从哪里开始。 I don't even know if what I am trying to do is possible. 我什至不知道我要做什么。

I was given an assignment to write a code that gets a string that resembles a variable declaration, for example int x,y; 我被分配编写一个代码,该代码获得类似于变量声明的字符串,例如int x,y; is a valid input. 是有效的输入。 char c,*cptr,carray[80]; is another example of valid input. 是有效输入的另一个示例。

The code will create what the user inputs, and will print how much memory it took. 该代码将创建用户输入的内容,并打印出它占用了多少内存。 For instance, in the first example ( int x,y; ) the code will create 2 integers, and print "x requires 4 bytes, y requires 4 bytes". 例如,在第一个示例( int x,y; )中,代码将创建2个整数,并显示“ x需要4个字节,y需要4个字节”。

In the second example, the code will create a character, a pointer to a character, and a string with 80 characters, and will print "c requires 1 byte, cptr requires 4 bytes, carray requires 80 bytes" 在第二个示例中,代码将创建一个字符,一个字符指针和一个包含80个字符的字符串,并显示“ c需要1个字节,cptr需要4个字节,carray需要80个字节”

Is this even possible? 这有可能吗? It is not valid code to declare variables after the beginning of the code. 在代码开头之后声明变量是无效的代码。 They must be declared before anything else in C. So I don't see a way to do this... 必须在C中的其他任何东西之前声明它们。因此,我看不到这样做的方法...

This is a parsing problem -- you need to parse the input string and figure out what it means. 这是一个解析问题-您需要解析输入字符串并找出含义。 You don't need to actually "create" anything, you just need to figure out the sizes of the variables that the compiler would create for that code. 您不需要实际“创建”任何东西,只需要弄清楚编译器将为该代码创建的变量的大小。

Parsing actually a very large subject, with lots of books written about it and tools written to make it easier. 解析实际上是一个非常大的主题,为此编写了许多书籍,并编写了一些使它变得更容易的工具。 While you could use a tool like antlr or bison to complete this task, they're probably overkill -- a simple recursive descent hand-written parser is probably the best approach. 虽然您可以使用antlrbison之类的工具来完成此任务,但它们可能会过高-一个简单的递归式手写解析器可能是最好的方法。

Something like: 就像是:

const char *parse_declaration(const char *p) {
    /* parse a declaration, printing out the names and sizes of the variables
     * 'p' points at the beginning of the string containing the declaration, and the
     * function returns the pointer immediately after the end or NULL on failure */
    int size;
    if (!(p = parse_declspecs(p, &size))) return 0;
    do {
        const char *name;
        int namelen, declsize;
        if (!(p = parse_declarator(p, size, &name, &namelen, &declsize))) return 0;
        printf("%.*s requires %d bytes\n", namelen, name, declsize);
        p += strspn(p, " \t\r\n");  /* skip whitespace */
    } while (*p++ == ',');
    if (p[-1] != ';') return 0;
    return p;
}

const char *parse_declspecs(const char *p, int *size) {
    /* parse declaration specifiers (a type), and output the size of that type
     * p points at the string to be parsed, and we return the point after the declspec */
    p += strspn(p, " \t\r\n");
    if (!isalpha(*p)) return 0;
    int len = 0;
    while (isalnum(p[len])) len++;
    if (!strncmp(p, "char", len)) {
        *size = sizeof(char);
          return p+len; }
    if (!strncmp(p, "int", len)) {
        *size = sizeof(int);
        return p+len; }
    ... more type tests here ...
    if (!strncmp(p, "unsigned", len)) {
        p += len;
        p += strspn(p, " \t\r\n");
        if (!isalpha(*p)) {
            *size = sizeof(unsigned);
            return p; }
        while (isalnum(p[len])) len++;
        if (!strncmp(p, "int", len)) {
            *size = sizeof(unsigned int);
            return p+len; }
        ... more type tests here ...
    }
    return 0;
}

const char *parse_declarator(const char *p, int typesize, const char **name, int *namelen, int *declsize) {
    /* parse a declarator */
    p += strspn(p, " \t\r\n");
    while (*p == '*') {
        typesize = sizeof(void *); /* assuming all pointers are the same size...*/
        p++;
        p += strspn(p, " \t\r\n"); }
    declsize = typesize;
    if (isalpha(*p)) {
        *name = p;
         while (isalnum(*p) | *p == '_') p++;
        *namelen = p - *name;
    } else if (*p == '(') {
        if (!(p = parse_declarator(p+1, typesize, name, namelen, declsize))) return 0;
        p += strspn(p, " \t\r\n");
        if (*p++ != ')') return 0;
    } else
        return 0;
    p += strspn(p, " \t\r\n");
    while (*p == '[') {
        int arraysize, len;
        if (sscanf(++p, "%d %n", &arraysize, &len) < 1) return 0;
        p += len;
        declsize *= arraysize;
        if (*p++ != ']') return 0;
        p += strspn(p, " \t\r\n"); }
    return p;
}

should get you started... 应该让您开始...

If you are trying to execute input code dynamically, to my knowledge that would not be possible without storing the code and then compiling again. 如果您尝试动态执行输入代码,据我所知,如果不存储代码然后重新编译,这是不可能的。 This however seems like a very nasty and lengthy approach. 但是,这似乎是一种非常讨厌且冗长的方法。 If all you are trying to do however is calculate the size of declarations from input, what I would do is take the string received, call a function that analyzes/decomposes the string. 但是,如果您只是想从输入中计算声明的大小,那么我将采取接收到的字符串的方式,调用一个分析/分解字符串的函数。 So for example if the string has "int", "char", etc.. I know would know what kind of declaration I am dealing with, and after I know what declaration I am dealing with I could just count the number of variables declared and keep a counter in your example it was x,y. 因此,例如,如果字符串包含“ int”,“ char”等。我知道我将要处理的是哪种声明,在知道了要处理的声明之后,我只需计算已声明的变量数即可并在您的示例中保留一个计数器,即x,y。 I would a loop on the counter and calculate the sizeof the type of declaration and how many were declared. 我会在计数器上循环并计算声明类型的大小以及声明了多少。

Sure, it's possible; 当然可以。 it's just a bit of work. 这只是一点工作。 You're going to have to study C declaration syntax, and then write the code to recognize it (basically a small compiler front end). 您将必须学习C声明语法,然后编写代码以识别它(基本上是一个小的编译器前端)。

For example, in the declaration 例如,在声明中

char c, *cptr, carray[80];

you have a sequence of tokens : 您有一系列令牌

char c , * cptr , carray [ 80 ] ;

which will be recognized as a type specifier ( char ) followed by three declarators ; 这将被认为类型说明符char ),其后是三个声明 ; a direct declarator, a pointer declarator, and an array declarator. 直接声明符,指针声明符和数组声明符。

You can create the space for the objects dynamically using malloc or calloc . 您可以使用malloccalloc为对象动态创建空间。 Then you'll need to create some kind of table to map the identifier (the variable name) to the dynamically-created object. 然后,您需要创建某种表以将标识符(变量名)映射到动态创建的对象。 You won't be able to treat these things as regular variables in regular C code; 您将无法在常规C代码中将这些内容视为常规变量。 you're going to be doing a lot of table lookups and dereferencing. 您将要进行很多表查找和取消引用。

Sure, you could do this with a type of parser. 当然,您可以使用一种解析器来执行此操作。 Assuming that you do not want to actually execute the code that you are given, you could read the string and then count how many times a variable of each specific type is declared, and calculate the amount of memory thusly. 假设您不想实际执行给出的代码,则可以读取字符串,然后计算声明每种特定类型的变量的次数,从而计算出内存量。 But, depending on the requirements of the professor, you may run into a view different issues. 但是,根据教授的要求,您可能会遇到不同的问题。

In particular, the sizes of different types will likely be different on each processor. 特别是,每个处理器上不同类型的大小可能会有所不同。 With the exception of char , you need to account for this. 除了char ,您需要考虑这一点。 This is easy if you are analyzing the memory requirements for the computer that your program is executing on, as you could just have const variables whose values are assigned via sizeof to get the sizes, but if not, your program is more difficult, especially since you cannot presume to know the size of any variable. 如果您要分析正在执行程序的计算机的内存需求,这很容易,因为您可能只有const变量,而这些变量的值是通过sizeof分配的,以获取大小,但是如果不是,则您的程序会更加困难,尤其是因为您不能假定知道任何变量的大小。

Secondly, struct s will be a problem do to some of the more interesting rules of C. Do you need to account for them? 其次,对于一些更有趣的C规则, struct s是一个问题。您是否需要考虑它们?

So, this is entirely possible, because contrary to what you stated in your question, your code doesn't have to "create" a variable at all - it can just create an in-memory total for each type and print them out when done. 因此,这完全有可能,因为与您在问题中所说的相反,您的代码根本不需要“创建”变量-它可以为每种类型创建一个内存总计,并在完成后将其打印出来。

Figured I would post my solution just incase anyone is interested 想通了我会发布我的解决方案,以防万一有人感兴趣

void* q5(char* str_in)
{
    char runner;
    int i=0,memory,counter=0,arr_size;
    runner=str_in[i];
    while(1)
    {
        if(runner=='i') //the input is integer
        {
            memory=sizeof(int);
            break;
        }
        if(runner=='c') //input is char
        {
            memory=sizeof(char);
            break;
        }
        if(runner=='d') //input is double
        {
            memory=sizeof(double);
            break;
        }
        if(runner=='s') //input is short
        {
            memory=sizeof(short);
            break;
        }
        if(runner=='l') //input is long
        {
            memory=sizeof(long);
            break;
        }
        if(runner=='f') //input is float
        {
            memory=sizeof(float);
            break;
        }
    } //we know the type of data, skip in the string until first variable
    while(runner!=' ') //advance until you see empty space, signaling next variable
    {
        i++;
        runner=str_in[i];
    }
    while(runner==' ') //advance until you encounter first letter of new variable
    {
        i++;
        runner=str_in[i];
    } //runner is now first letter of first variable
    while(runner!=';') //run on the string until its over
    {
        if(runner==',') //if its ',', then spaces will occur, skip all of them to first char that isnt space
        {
            i++;
            runner=str_in[i];
            while(runner==' ')
            {
                i++;
                runner=str_in[i];
            } //runner now points to first letter of variable
            continue;
        }
        if(runner=='*') //current variable is a pointer
        {
            counter=counter+4; //pointers are always 4 bytes regardless of type!
            i++;
            runner=str_in[i];
            while((runner!=',')&&(runner!=';')) //while runner is still on this variable
            {
                printf("%c",runner);
                i++;
                runner=str_in[i];
            }
            printf(" requires 4 bytes\n"); //now runner is the first character after the variable we just finished
            continue;
        }
        while((runner!=',')&&(runner!=';')) //now is the case that runner is the first letter of a non pointer variable
        {
            printf("%c",runner);
            i++;
            runner=str_in[i];
            if((runner==',')||(runner==';')) //we are done
            {
                printf(" requires %d bytes\n",memory);
                counter+=memory;
                continue;
            }
            if(runner=='[') //this variable is an array
            {
                printf("[");
                i++;
                runner=str_in[i]; //runner is now MSB of size of array
                arr_size=0;
                while(runner!=']')
                {
                    printf("%c",runner);
                    arr_size*=10;
                    arr_size=arr_size+runner-48; //48 is ascii of 0
                    i++;
                    runner=str_in[i];
                } //arr_size is now whats written in the [ ]
                printf("] requires %d bytes\n",arr_size*memory);
                counter+=arr_size*memory;
                i++;
                runner=str_in[i]; // should be ',' since we just finished a variable
                continue;
            }
        }
    }
    printf("Overall %d bytes needed to allocate\n",counter);
    return (malloc(counter));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM