Thread: K&R Exercise 5-20 : bsearch Error when compiled

  1. #1
    Registered User
    Join Date
    Jun 2013
    Posts
    9

    K&R Exercise 5-20 : bsearch Error when compiled

    Problem
    Expand dcl to handle declarations with function argument types, qualifiers like const, and so on.
    Answer:
    main.c
    Code:
    #include "extern.h"
    #include <string.h>
    #include <ctype.h>
    
    
    
    
    enum { NAME, PARENS, BRACKETS};
    enum {NO, YES};
    
    
    void dcl (void);
    void dirdcl(void);
    void errmsg(char *);
    int gettoken(void);
    
    
    int tokentype;
    char token[MAXTOKEN];
    char name[MAXTOKEN];
    char datatype[MAXTOKEN];
    char out[1000];
    int prevtoken;
    
    
    int main()  /* convert declaration to words */
    {
        while (gettoken() != EOF) { /* 1st token on line */
             strcpy(datatype, token);   /* is the datatype */
             out[0] = '\0';
             dcl();         /* parse rest of line */
             if (tokentype != '\n')
                printf("syntax error\n");
             printf("%s:  %s %s\n", name, out, datatype);
        }
        return 0;
    }
    
    
    void dcl (void)
    {
        int ns;
        for(ns = 0; gettoken() == '*'; )
            ns++;
        dirdcl();
        while(ns-- > 0)
            strcat(out, " pointer to");
    }
    
    
    void dirdcl(void)
    {
        int type;
        void parmdcl(void);
        if(tokentype == '(') {
            dcl();
            if(tokentype != ')')
                errmsg("error: missing )\n");
        } else if (tokentype == NAME) {
            if(name[0] == '\0')
                strcpy(name, token);
        } else
            prevtoken = YES;
        while((type = gettoken()) == PARENS || type == BRACKETS || type == '(')
            if(type == PARENS)
                strcat(out, "function returning");
            else if (type == '(') {
                strcat(out, " function expecting");
                parmdcl();
                strcat(out, " and returning");
            } else {
                strcat(out, " array");
                strcat(out, token);
                strcat(out, " of");
            }
    }
    
    
    void errmsg(char *msg)
    {
        printf("%s",msg);
        prevtoken = YES;
    }
    parmdcl.c
    Code:
    #include "extern.h"
    #include <string.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    
    enum { NAME, PARENS, BRACKETS};
    enum { NO, YES};
    
    
    void dcl(void);
    void errmsg(char *);
    void dclspec(void);
    int typespec(void);
    int typequal(void);
    int compare(char **, char **);
    int gettoken(void);
    
    
    int tokentype;
    char token[MAXTOKEN];
    char name[MAXTOKEN];
    char datatype[MAXTOKEN];
    char out[MAXTOKEN];
    int prevtoken;
    
    
    void parmdcl(void)
    {
            do {
                dclspec();
            } while(tokentype == ',');
            if(tokentype != ')')
                errmsg("missing ) in parameter declaration\n");
    }
    
    
    void dclspec (void)
    {
        char temp[MAXTOKEN];
        temp[0] = '\0';
        gettoken();
        do {
            if (tokentype != NAME) {
                prevtoken = YES;
                dcl();
            } else if (typespec() == YES) {
                    strcat(temp, " ");
                    strcat(temp, token);
                    gettoken();
            } else if(typequal() == YES) {
                    strcat(temp, " ");
                    strcat(temp, token);
                    gettoken();
            } else
                errmsg("unknown type in parameter list \n");
        } while (tokentype != ',' && tokentype != ')');
        strcat(out, temp);
        if(tokentype == ',')
            strcat(out, ",");
    }
    
    
    int typespec(void)
    {
        static char *types[] = {
            "char",
            "int",
            "void"
        };
        char *pt = token;
        
        if (bsearch(&pt, types, sizeof(types)/sizeof(char *), sizeof(char *), compare)==NULL)
            return NO;
        else
            return YES;
    }
    
    
    int typequal(void)
    {
        static char *typeq[] = {
                "const",
                "volatile"
        };
        char *pt = token;
        
        if(bsearch(&pt, typeq, sizeof(typeq)/sizeof(char *), sizeof(char *), compare) == NULL)
            return NO;
        else
            return YES;
        
    }
    
    
    int compare(char **s, char **t)
    {
        return strcmp(*s, *t);
    }
    gettoken.c
    Code:
    #include "extern.h"
    #include <ctype.h>
    #include <string.h>
    
    
    enum {NAME, PARENS, BRACKETS};
    enum {NO, YES};
    
    
    int tokentype;
    char token[MAXTOKEN];
    int prevtoken = NO;
    
    
    int gettoken(void)
    {
        int c, getch(void);
        void ungetch(int);
        char *p = token;
        
        if (prevtoken == YES) {
            prevtoken = NO;
            return tokentype;
        }
        while((c = getch()) == ' ' || c == '\t')
            ;
        if (c == '(') {
            if ((c = getch()) == ')') {
                strcpy (token, "()");
                return tokentype = PARENS;
            } else {
                ungetch(c);
                return tokentype = '(';
            }
        } else if (c == '[') {
            for(*p++ = c; (*p++ = getch()) != ']'; )
                ;
            *p = '\0';
            return tokentype = BRACKETS;
        } else if (isalpha(c)) {
            for(*p++ = c; isalnum(c = getch()); )
                *p++ = c;
            *p = '\0';
            ungetch(c);
            return tokentype = NAME;
        } else
            return tokentype = c;
    }
    
    
    #define BUFSIZE 100
     
    char  buf[BUFSIZE]; /* buffer for ungetch */
    int   bufp = 0;     /* next free position in buf */
     
    int getch(void)     /* get a (possibly pushed back) character */
    {
        return (bufp > 0)  ?  buf[--bufp]  :  getchar();
    }
     
    void ungetch(int c) /* pretend to push character back on input */
    {
        if (bufp >= BUFSIZE) 
            printf("ungetch:  too many characters\n");
        else 
            buf[bufp++] = c;
    }
    extern.h
    Code:
    #include <stdio.h>
    extern int tokentype;
    extern char token[];
    extern char name[];
    extern char datatype[];
    extern char out[];
    extern int prevtoken;
    
    
    #define MAXTOKEN 100
    gcc main.c parmdcl.c gettoken.c -Wall -Werror -pedantic -g -o dcl.exe
    Error: passing argument 5 of 'bsearch' from incompatible pointer type [-Werror]

    So i think the 5th argument of bsearch doesn't seem to accept double pointers. The function compare()'s parameter have two double pointers because it will receive string arguments for the bsearch (from <stdlib.h>) to compare them if they are in the static char arrays, *typeq[] and *types[].

    The error lies in the functions typespec() and typequal() in the parmdcl.c sourcefile. Anyone know how to make this work?
    Last edited by BinaryProgamer; 06-25-2013 at 02:49 PM.

  2. #2
    Registered User
    Join Date
    Mar 2011
    Posts
    546
    the compiler wants a compare function that matches the prototype required by bsearch, namely int compare(const void *a,const void *b); your compare function has a different prototype. change compare to the be int compare(const void *a,const void *b) and in the function itself cast the void *'s to whatever type you need.

  3. #3
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    1. Are you not compiling gettoken.c as well?
    2. Why are you redefining your global variables in each of your source files? You know that the linker is going to complain when it has to merge them to build the executable right? If you want to use globals from one file in another file, then you define them extern in a scope visible to all the source files that need access to those globals and then you actually declare them in one (and only one) source file, not multiple source files.
    3. The last argument of bsearch function is of type int (*compar)(const void*,const void*), what you give it has to match that expected signature, your compare function does not.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  4. #4
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Another quick note:
    Code:
    bsearch(&pt, typeq, sizeof(typeq)/sizeof(char *), sizeof(char *), compare)
    It's good that you used the variable name (typeq) in the first sizeof expression, however you should use it in both. What you're really after is the size of one element of the typeq array, so do this:
    Code:
    bsearch(&pt, typeq, sizeof(typeq)/sizeof(typeq[0]), sizeof(typeq[0]), compare)
    The main advantage of using the variable name instead of the type is that, if you change the type of typeq, your sizeof expressions, and thus your bsearch call, will still work correctly. If you only do that to part of the expression, you're forfeiting this advantage.

  5. #5
    Registered User
    Join Date
    Jun 2013
    Posts
    9
    I did what you told me and the code now works. Can you check if what i did was the right thing?

    parmdcl.c
    Code:
    ...
    int compare(const void *s, const void *t)
    {
        char **chs;
        char **cht;
        chs = (char **) s;
        cht = (char **) t;
        return strcmp(*chs, *cht);
    }
    ...
    Quote Originally Posted by hk_mp5kpdw
    2. Why are you redefining your global variables in each of your source files? You know that the linker is going to complain when it has to merge them to build the executable right? If you want to use globals from one file in another file, then you define themextern in a scope visible to all the source files that need access to those globals and then you actually declare them in one (and only one) source file, not multiple source files.
    Is this correct? I redefined them only in the main source file as what you told me to do.
    extern.h
    Code:
    #include <stdio.h>
    extern int tokentype;
    extern char token[];
    extern char name[];
    extern char datatype[];
    extern char out[];
    extern int prevtoken;
    
    
    
    
    enum {NAME, PARENS, BRACKETS};
    enum {NO, YES};
    
    
    #define MAXTOKEN 100
    main.c
    Code:
    ...
    int tokentype;
    char token[MAXTOKEN];
    char name[MAXTOKEN];
    char datatype[MAXTOKEN];
    char out[1000];
    ...
    gettoken.c
    Code:
    ...
    int prevtoken = NO;
    ...
    in parmdcl.c i didn't declare any global variables since all of them are already redefined in a source file

    Anyway, thanks for all your help. The code now works.
    Last edited by BinaryProgamer; 06-28-2013 at 09:17 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Exercise reverse array . I can't to find error .
    By ToNy_ in forum C Programming
    Replies: 8
    Last Post: 12-15-2011, 04:02 PM
  2. Replies: 1
    Last Post: 03-12-2008, 12:10 AM
  3. Compiled without error but Result varies!!
    By RahulDhanpat in forum C Programming
    Replies: 10
    Last Post: 02-12-2008, 10:32 AM
  4. Compiled error?
    By name|ess` in forum C++ Programming
    Replies: 2
    Last Post: 06-14-2004, 08:48 AM
  5. VC 6.0 compiled error
    By alan4100 in forum Windows Programming
    Replies: 4
    Last Post: 09-17-2001, 03:10 PM