boyd@necisa.ho.necisa.oz (Boyd Roberts) (10/31/90)
In article <1005@christopher-robin.cs.bham.ac.uk> ptf@uk.ac.bham.cs (Paul Flinders <FlindersPT>) writes: > >in foo.h: > extern void ddprintf(const char *fmt, ...); > >BUT in foo.c: > > void ddprintf(va_alist) > va_dcl; > >this causes problems. Right on! The function prototypes are just stupid. I shouldn't have to go: extern gore *good(const char *vomit); to get the functionality of type checking of function arguments. The compiler and loader should do it. The computer is there to do the tedious stuff for you. The computer is (was) your friend. There should be enough stuff in the `.o' to specify all the calls to my function good() complete with the types of all the arguments. The `.o' that contains good() should contain extra information of the types of the arguments to good(). Then the loader should cross check all the calls with the declaration and then _refuse_ to load unless everything check out just right. Yes, that's right -- _refuse_. Now this would remove function prototyping once and for all. But, before you say `what about var args'. Things that are var arged should be specified as such on the command line. You say how many arguments to check. Now, I've seen it done and it's good. My old mate brucee did it `back in the hippy days' and it runs at the Labs. Ever heard of `cyntax'? Check out cyntax(1) in the Ninth Edition manual. Boyd Roberts boyd@necisa.ho.necisa.oz.au ``When the going gets wierd, the weird turn pro...''
rjc@uk.ac.ed.cstr (Richard Caley) (11/01/90)
In article <1906@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes:
Right on! The function prototypes are just stupid. I shouldn't have to go:
extern gore *good(const char *vomit);
to get the functionality of type checking of function arguments.
The compiler and loader should do it.
Ok, so what happens to code which never sees the loader?
I want my errors when I compile things, not when some poor guy tries
to use it.
Even in less extreme cases, having the loader do all the checking
would mean you got no error checking until you did a full compile and
link. For even fairly small programs that will be unacceptable ``Well,
yeah, we really do need the cray, we have to recompile the entire
system every three minutes during development.''
Which is not to say that the linker shouldn't _also_ check the types.
So should the run time system and the disc driver, if I had my way :-)
--
rjc@uk.ac.ed.cstr Paranoid of Leith
salomon@ccu.umanitoba.ca (Dan Salomon) (11/02/90)
In article <RJC.90Nov1145211@brodie.uk.ac.ed.cstr> rjc@uk.ac.ed.cstr (Richard Caley) writes: >In article <1906@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: > > > Right on! The function prototypes are just stupid. > > I shouldn't have to type: > > extern gore *good(const char *vomit); > > to get the functionality of type checking of function arguments. > > The compiler and loader should do it. > > I want my errors when I compile things, not when some poor guy tries > to use it. > You are both right. Repeatedly typing function prototypes is a tedious waste of time, but we really would like type errors reported at compile time. A possible solution would be to have a utility for building libraries of function prototypes from source code. The compiler could check source code usage against usage in this library. The linker would have to repeat the check to make sure that the prototype library didn't get out of synch with the object library. -- Dan Salomon -- salomon@ccu.UManitoba.CA Dept. of Computer Science / University of Manitoba Winnipeg, Manitoba, Canada R3T 2N2 / (204) 275-6682
peter@ficc.ferranti.com (Peter da Silva) (11/03/90)
In article <1990Nov2.030556.27759@ccu.umanitoba.ca> salomon@ccu.umanitoba.ca (Dan Salomon) writes: > You are both right. Repeatedly typing function prototypes is a tedious > waste of time, but we really would like type errors reported at compile > time. Ever hear of include files? > A possible solution would be to have a utility for building libraries > of function prototypes from source code. The Manx compiler for the Amiga has a flag that lets you build include files from the source. -- Peter da Silva. `-_-' +1 713 274 5180. 'U` peter@ferranti.com
stever@Octopus.COM (Steve Resnick ) (11/03/90)
In article <1990Nov2.030556.27759@ccu.umanitoba.ca> salomon@ccu.umanitoba.ca (Dan Salomon) writes: >In article <RJC.90Nov1145211@brodie.uk.ac.ed.cstr> rjc@uk.ac.ed.cstr (Richard Caley) writes: >>In article <1906@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: >> >> > Right on! The function prototypes are just stupid. >> > I shouldn't have to type: >> > extern gore *good(const char *vomit); >> > to get the functionality of type checking of function arguments. >> > The compiler and loader should do it. >> >> I want my errors when I compile things, not when some poor guy tries >> to use it. >> > >You are both right. Repeatedly typing function prototypes is a tedious >waste of time, but we really would like type errors reported at compile >time. > >A possible solution would be to have a utility for building libraries >of function prototypes from source code. The compiler could check >source code usage against usage in this library. The linker would have >to repeat the check to make sure that the prototype library didn't get >out of synch with the object library. >-- > Some C compilers do this for you. Microsoft C 6.0 will, as an option generate declarations (prototypes) to stdout when asked to. This has saved me the tedium of typing all those prototypes in myself! :) Cheers! Steve -- ---------------------------------------------------------------------------- steve.resnick@f105.n143.z1.FIDONET.ORG - or - apple!camphq!105!steve.resnick Flames, grammar errors, spelling errrors >/dev/nul The Asylum OS/2 BBS - (408)263-8017 IFNA 1:143/105.0
salomon@ccu.umanitoba.ca (Dan Salomon) (11/03/90)
In article <MKU65ZE@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes: >In article <1990Nov2.030556.27759@ccu.umanitoba.ca> salomon@ccu.umanitoba.ca (Dan Salomon) writes: >> You are both right. Repeatedly typing function prototypes is a tedious >> waste of time, but we really would like type errors reported at compile >> time. >> A possible solution would be to have a utility for building libraries >> of function prototypes from source code. > >Ever hear of include files? > Actually, include files aren't quite the same as a library of function prototypes. The distinction is the same as between an object library, and a file full of object modules. In addition to the problem of keeping the include files up to date, there is also the problem of filling up your symbol table with dozens of unused symbols. Processing all the prototypes in an include file is slower than a search for and processing of only the ones actually needed. This is especially a problem when a large collection of functions are grouped together in a common directory, but in separate files. Such an organization speeds up the compilation of large projects, by allowing the recompilation of only the out-of-date functions. If each of the files has to include a large number of prototypes, the some of the speed up is lost. Once your set of functions is running, what tool do you use to assemble all the prototypes into up-to-date include files? Such tools exists for object modules, perhaps similar tools are needed for function prototypes. -- Dan Salomon -- salomon@ccu.UManitoba.CA Dept. of Computer Science / University of Manitoba Winnipeg, Manitoba, Canada R3T 2N2 / (204) 275-6682
rjc@uk.ac.ed.cstr (Richard Caley) (11/03/90)
In article <1990Nov2.030556.27759@ccu.umanitoba.ca> salomon@ccu.umanitoba.ca (Dan Salomon) writes: In article <RJC.90Nov1145211@brodie.uk.ac.ed.cstr> rjc@uk.ac.ed.cstr (Richard Caley) writes: > I want my errors when I compile things, not when some poor guy tries > to use it. You are both right. Repeatedly typing function prototypes is a tedious waste of time, but we really would like type errors reported at compile time. Since there is, as far as I know, no difference between the prototype and the definition except for the `;', there is no extra typing to do. Just copy the definition. Now I realise there are some brain dead editors out there and I have upon occasion written C using `cat', but I assume that anything anyone is willing to use for more than trivial coding can manage a textual copy. -- rjc@uk.ac.ed.cstr
peter@ficc.ferranti.com (Peter da Silva) (11/04/90)
In article <1990Nov3.122432.24738@ccu.umanitoba.ca> salomon@ccu.umanitoba.ca (Dan Salomon) writes: > Actually, include files aren't quite the same as a library of function > prototypes. The distinction is the same as between an object library, > and a file full of object modules. True, there is an efficiency consideration. I don't tend to have a single module or collection of modules that require more than a handful of files, so this hasn't been a problem. Plus, who says include files have to be stored in files? The C standard doesn't. This is an implementation detail. :-> Yeh, it's a problem, but it's not a show stopper. > In addition to the problem of > keeping the include files up to date, That is the real problem. You need a tool to extract the prototypes from a file. Beyond that, make will do the rest. > Processing all the prototypes in an include file is slower than a search > for and processing of only the ones actually needed. Precompiled include files. Some compilers have 'em. I've never had to use 'em myself, but my home machine has plenty of MIPs and IoStones. -- Peter da Silva. `-_-' +1 713 274 5180. 'U` peter@ferranti.com
Markku.Savela@tel.vtt.fi (Markku Savela) (11/04/90)
In article <-BV6Q16@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes: >> In addition to the problem of >> keeping the include files up to date, >That is the real problem. You need a tool to extract the prototypes from >a file. Beyond that, make will do the rest. Yes, but this is a bad habit. The include file should be the external specification of the module. Any changes in external specification shouldn't be so frequent, if you have the code done right. -- Markku Savela (savela@tel.vtt.fi), Technical Research Centre of Finland Telecommunications Laboratory, Otakaari 7 B, SF-02150 ESPOO, Finland
jaakola@cc.helsinki.fi (11/05/90)
In article <RJC.90Nov3153129@brodie.uk.ac.ed.cstr>, rjc@uk.ac.ed.cstr (Richard Caley) writes: > Since there is, as far as I know, no difference between the prototype > and the definition except for the `;', there is no extra typing to do. > Just copy the definition. Why do *I* have to do the copying for all my functions, while there's the compiler which a) is supposed to work for me and not vice versa and b) should know ANSI peculiarities better than I do? It's okay for me to make an include file, where I declare functions that are visible to other modules. But consider the following example: static void auxiliary_func(a) /* private helper-function */ int a; { ... } void visible_fun(b) int b; { ... auxiliary_func(b+1); /* should be checked */ ... } The point is, why should I have to tell the compiler twice the type of auxiliary_func? The prototype should be necessary only if I make a forward reference to make it easier for the compiler to check types in a single pass. I think the function definition tells unambiguously the types, so I should not have to watch warnings such as "function definition used as a prototype" (Microsoft C 5.1). Ok, I could turn off such warnings in Microsoft C 5.1, but this turns off some useful checks as a side-effect! Please, Microsoft, make a "prototypes-off" switch into Microsoft C for me! I do not want to bother keeping prototypes of such axiliary helper-functions up-to-date. "You could use an automatic prototype builder," I hear you say. Yeah, I could, but why couldn't that builder be built into the compiler, so that I didn't have to burden my brains to use it? After all, those helper-functions tend to change much when I fine-tune the implementation of my module. Another ANSI-misfeature is the ability to make declarations such as: int foo(int b, char *s) I like much more the old style int foo(b,s) int b; /* the b means ... blahblahblah */ char *s; /* the s means ... */ This is better, because you can have function name and args on the same line, so that you can query all function names by grep-like tools (grep outputs only single lines, which is very compact and - I think - readable format). If you have much args, this way you can still put all of them on a single line. After the first line I tell the types of each arg and use comments after each args as shown above.
hurtta@cs.Helsinki.FI (Kari Hurtta) (11/05/90)
In article <3933.27353319@cc.helsinki.fi> jaakola@cc.helsinki.fi writes: It's okay for me to make an include file, where I declare functions that are visible to other modules. But consider the following example: static void auxiliary_func(a) /* private helper-function */ int a; { ... } void visible_fun(b) int b; { ... auxiliary_func(b+1); /* should be checked */ ... } The point is, why should I have to tell the compiler twice the type of auxiliary_func? The prototype should be necessary only if I make a forward reference to make it easier for the compiler to check types in a single pass. I think the function definition tells unambiguously the types, so I should not have to watch warnings such as "function definition used as a prototype" (Microsoft C 5.1). Ok, I could turn off such warnings in Microsoft C 5.1, but this turns off some useful checks as a side-effect! Please, Microsoft, make a "prototypes-off" switch into Microsoft C for me! Why not: static void auxiliary_func(int a) { ... } void visible_fun(int b) { ... auxiliary_func(b+1); ... } - K E H ( hurtta@cc.Helsinki.FI hurtta@cs.Helsinki.FI HURTTA@FINUH.BITNET )
peter@ficc.ferranti.com (Peter da Silva) (11/06/90)
In article <3933.27353319@cc.helsinki.fi> jaakola@cc.helsinki.fi writes: > static void auxiliary_func(a) /* private helper-function */ > int a; > { > ... > } If you do this: static void auxilary_func(int a) { ... } Everything will work fine. You only need declare it once. Just do it right the first time and you won't have to do it again (my father always used to tell me that). -- Peter da Silva. `-_-' +1 713 274 5180. 'U` peter@ferranti.com
rmartin@clear.com (Bob Martin) (11/06/90)
In article <1906@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: > > Right on! The function prototypes are just stupid. I shouldn't have to go: > > extern gore *good(const char *vomit); > > to get the functionality of type checking of function arguments. > The compiler and loader should do it. > The C++ compiler does this. If you declare a function one way and use it in another, say with different type arguments, then the program won't link. C++ does this by mangling the return type and argument types into the function name. Thus when you declare a function: int x(int y) the compiler generates a new name for the function which is what the loader sees. This name would specify that the function's name was x, that it returned an int and that it had a single int parameter. So if you screw up your declarations, or attempt to use implicit declarations (bad style), you cannot get a runtime error becuase of a type mismatch. The linker will catch the problem. -- By the way, this technique of mangling the function names means that int x(int y); and double x(double y); are completely different functions. You can declare both of them, define them separately and call the proper function by making sure that the types are correct. +----------------------+---------------------------------------------+ | Robert C. Martin | The authors opinions are his own and do not | | rmartin@clear.com | represent the opinions of his employer. | | uunet!clrcom!rmartin | | +----------------------+---------------------------------------------+ -- +----------------------+---------------------------------------------+ | Robert C. Martin | The authors opinions are his own and do not | | rmartin@clear.com | represent the opinions of his employer. |
rjc@uk.ac.ed.cstr (Richard Caley) (11/06/90)
In article <3933.27353319@cc.helsinki.fi> jaakola@cc.helsinki.fi writes: It's okay for me to make an include file, where I declare functions that are visible to other modules. But consider the following example: static void auxiliary_func(a) /* private helper-function */ int a; { ... } void visible_fun(b) int b; { ... auxiliary_func(b+1); /* should be checked */ ... } The point is, why should I have to tell the compiler twice the type of auxiliary_func? You don't. In the above case you havn't even told it once. If you did... static void auxiliary_func(int a) { ... } you wouldn't need to type anything more. Or if you did that would be a massive compiler misfeature. This even saves you a couple of characters :-) Ok, I could turn off such warnings in Microsoft C 5.1, but this turns off some useful checks as a side-effect! Please, Microsoft, make a "prototypes-off" switch into Microsoft C for me! If the compiler really does complain in the case where you give the full type in the function definition then I agree that the writers had better start watching out for mobs of irate users coming after them with pitchforks and flaming torches. Someone must make a working C compiler for your machine... -- rjc@uk.ac.ed.cstr
darcy@druid.uucp (D'Arcy J.M. Cain) (11/06/90)
In article <3933.27353319@cc.helsinki.fi> jaakola@cc.helsinki.fi writes: >Why do *I* have to do the copying for all my functions, while there's >the compiler which a) is supposed to work for me and not vice versa > and b) should know ANSI peculiarities better than I do? > > static void auxiliary_func(a) /* private helper-function */ > int a; > { > ... > } > > void visible_fun(b) > int b; > { > ... > auxiliary_func(b+1); /* should be checked */ > ... > } > >The point is, why should I have to tell the compiler twice the type of >auxiliary_func? The prototype should be necessary only if I make a All ANSI compilers that I have used do exactly that. You do of course have to declare the function in an ANSI compliant way but once you do it is effectively prototyped from that point on. In the above example replace the first two lines with: static void auxiliary_func(int a) /* private helper-function */ The only time that I have to retype (or copy) a prototype is when the function is used in a different module. > >Another ANSI-misfeature is the ability to make declarations such as: > > int foo(int b, char *s) > >I like much more the old style > > int foo(b,s) > int b; /* the b means ... blahblahblah */ > char *s; /* the s means ... */ > >This is better, because you can have function name and args on the same >line, so that you can query all function names by grep-like tools (grep >outputs only single lines, which is very compact and - I think - >readable format). If you have much args, this way you can still put all >of them on a single line. So that just means we need smarter tools, not that we should stand still for fear of disturbing something. > >After the first line I tell the types of each arg and use comments after >each args as shown above. Where suitable I do the same thing: int foo( int b, /* the b means ... blahblahblah */ char *s) /* the s means ... */ -- D'Arcy J.M. Cain (darcy@druid) | D'Arcy Cain Consulting | I support gun control. West Hill, Ontario, Canada | Let's start with the government! + 416 281 6094 |
brad@SSD.CSD.HARRIS.COM (Brad Appleton) (11/09/90)
I grabbed a PD prototype generator utility written in C (that I think works for both ANSI and K&R) not too long ago - its pretty small - here it is: I have a 10 line awk script that does it too but the C program is obviously a wee bit more portable ;-) Its only two files (a .c and a .h file). Actually its only one file - it can create its own .h file but you need to get it running first :-) Anyway - im sure some of you will find some use for it! Its written in K&R but Im sure it would be no problem to convert to ANSI. ______________________ "And miles to go before I sleep." ______________________ Brad Appleton brad@ssd.csd.harris.com Harris Computer Systems uunet!hcx1!brad Fort Lauderdale, FL USA ~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~ ------------------------------ cut here --------------------------------------- # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by brad on Thu Nov 8 11:41:53 EST 1990 # Contents: mkproto.c mkproto.h echo x - mkproto.c sed 's/^@//' > "mkproto.c" <<'@//E*O*F mkproto.c//' /* Program to extract function declarations from C source code */ /* Written by Eric R. Smith and placed in the public domain */ /* Thanks are due to Jwahar R. Bammi for fixing several bugs */ /* and providing the Unix makefiles. S. Manoharan included a */ /* Getopt() function and modified the code to handle C++ style */ /* comments and member functions. */ #if defined(__STDC__) && !defined(minix) #include <stddef.h> #include <stdlib.h> #else #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 extern char *malloc(); #endif #include <stdio.h> #include <ctype.h> #include <string.h> #define DEBUG(s) { if (dodebug) fputs(s, stderr); } /* */ /*#define DEBUG(s) /* */ #define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_')) #define ABORTED ( (Word *) -1 ) #define MAXPARAM 20 /* max. number of parameters to a function */ #define NEWBUFSIZ (20480*sizeof(char)) /* new buffer size */ typedef enum { false = 0, true = 1 } Boolean; Boolean newline_seen = true; /* are we at the start of a line */ Boolean dostatic = false; /* do static functions? */ Boolean donum = false; /* print line numbers? */ Boolean dopromote = true; /* promote certain sc-specifiers */ Boolean dohead = true; /* do file headers? */ Boolean dodebug = false; /* do debugging? */ Boolean docond = false; /* conditionalize for non-ANSI compilers */ long linenum = 1L; /* line number in current file */ int glastc = ' '; /* last char. seen by getsym() */ int inquote = 0; /* in a quote?? */ typedef struct word { struct word *next; char string[1]; } Word; #include "mkproto.h" /* * Routines for manipulating lists of words. */ Word *word_alloc(s) char *s; { Word *w; w = (Word *) malloc((unsigned)sizeof(Word) + strlen(s) + 1); /* ++jrb */ (void)strcpy(w->string, s); w->next = NULL; return w; } void word_free(w) Word *w; { Word *oldw; while (w) { oldw = w; w = w->next; free((char *)oldw); } } /* return the length of a list; empty words are not counted */ int List_len(w) Word *w; { int count = 0; while (w) { if (*w->string) count++; w = w->next; } return count; } /* Append two lists, and return the result */ Word *word_append(w1, w2) Word *w1, *w2; { Word *r, *w; r = w = word_alloc(""); while (w1) { w->next = word_alloc(w1->string); w = w->next; w1 = w1->next; } while (w2) { w->next = word_alloc(w2->string); w = w->next; w2 = w2->next; } return r; } /* see if the last entry in w2 is in w1 */ int foundin(w1, w2) Word *w1, *w2; { while (w2->next) w2 = w2->next; while (w1) { if (!strcmp(w1->string, w2->string)) return 1; w1 = w1->next; } return 0; } /* add the string s to the given list of words */ void addword(w, s) Word *w; char *s; { while (w->next) w = w->next; w->next = word_alloc(s); } /* given a list representing a type and a variable name, extract just * the base type, e.g. "struct word *x" would yield "struct word" */ Word *typelist(p) Word *p; { Word *w, *r; r = w = word_alloc(""); while (p && p->next) { if (p->string[0] && !ISCSYM(p->string[0])) break; w->next = word_alloc(p->string); w = w->next; p = p->next; } return r; } /* typefixhack: promote formal parameters of type "char", * "unsigned char", "short", or "unsigned short" to "int". */ void typefixhack(w) Word *w; { Word *oldw = 0; while (w) { if (*w->string) { if ( (!strcmp(w->string, "char") || !strcmp(w->string, "short") ) && (List_len(w->next) < 2) ) { if (oldw && !strcmp(oldw->string, "unsigned")) { oldw->next = w->next; free((char *)w); w = oldw; } (void)strcpy(w->string, "int"); } } w = w->next; } } /* read a character: if it's a newline, increment the line count */ int ngetc(f) FILE *f; { int c; c = getc(f); if (c == '\n') linenum++; return c; } /* read the next character from the file. If the character is '\' then * read and skip the next character. Any comment sequence is converted * to a blank. [ Both C and C++ style comments are considered - sam ] */ int fnextch(f) FILE *f; { int c, lastc, incomment; c = ngetc(f); while (c == '\\') { DEBUG("fnextch: in backslash loop\n"); c = ngetc(f); /* skip a character */ c = ngetc(f); } if (c == '/' && !inquote) { c = ngetc(f); if (c == '*') { /* C comments */ incomment = 1; c = ' '; DEBUG("fnextch: comment seen\n"); while (incomment) { lastc = c; c = ngetc(f); if (lastc == '*' && c == '/') incomment = 0; else if (c < 0) return c; } return fnextch(f); } else if ( c == '/' ) { /* C++ comments */ incomment = 1; c = ' '; DEBUG("fnextch: C++ comment seen\n"); while ( c != '\n' ) { c = ngetc(f); } incomment = 0; return fnextch(f); } else { if (c == '\n') linenum--; (void)ungetc(c, f); return '/'; } } return c; } /* Get the next "interesting" character. Comments are skipped, and * strings are converted to "0". Also, if a line starts with "#" * it is skipped. */ int nextch(f) FILE *f; { int c; c = fnextch(f); if (newline_seen && c == '#') { do { c = fnextch(f); } while (c >= 0 && c != '\n'); if (c < 0) return c; } newline_seen = (c == '\n') ? true : false; if (c == '\'' || c == '\"') { DEBUG("nextch: in a quote\n"); inquote = c; while ( (c = fnextch(f)) >= 0 ) { if (c == inquote) { inquote = 0; DEBUG("nextch: out of quote\n"); return '0'; } } DEBUG("nextch: EOF in a quote\n"); } return c; } /* * Get the next symbol from the file, skipping blanks. * Return 0 if OK, -1 for EOF. * Also collapses everything between { and } */ int getsym(buf, f) char *buf; FILE *f; { register int c; int inbrack = 0; DEBUG("in getsym\n"); c = glastc; while ((c > 0) && isspace(c)) { c = nextch(f); } DEBUG("getsym: spaces skipped\n"); if (c < 0) { DEBUG("EOF read in getsym\n"); return -1; } if (c == '{') { inbrack = 1; DEBUG("getsym: in bracket\n"); while (inbrack) { c = nextch(f); if (c < 0) { DEBUG("getsym: EOF seen in bracket loop\n"); glastc = c; return c; } if (c == '{') inbrack++; else if (c == '}') inbrack--; } (void)strcpy(buf, "{}"); glastc = nextch(f); DEBUG("getsym: out of in bracket loop\n"); return 0; } if (!ISCSYM(c)) { *buf++ = c; *buf = 0; glastc = nextch(f); DEBUG("getsym: returning special symbol\n"); return 0; } while (ISCSYM(c)) { *buf++ = c; c = nextch(f); } *buf = 0; glastc = c; DEBUG("getsym: returning word\n"); return 0; } /* * skipit: skip until a ";" or the end of a function declaration is seen */ int skipit(buf, f) char *buf; FILE *f; { int i; do { DEBUG("in skipit loop\n"); i = getsym(buf, f); if (i < 0) return i; } while (*buf != ';' && *buf != '{'); return 0; } /* * Get a parameter list; when this is called the next symbol in line * should be the first thing in the list. */ Word *getparamlist(f) FILE *f; { static Word *pname[MAXPARAM]; /* parameter names */ Word *tlist, /* type name */ *plist; /* temporary */ int np = 0; /* number of parameters */ int typed[MAXPARAM]; /* parameter has been given a type */ int tlistdone; /* finished finding the type name */ int sawsomething; int i; int inparen = 0; char buf[80]; DEBUG("in getparamlist\n"); for (i = 0; i < MAXPARAM; i++) typed[i] = 0; plist = word_alloc(""); /* first, get the stuff inside brackets (if anything) */ sawsomething = 0; /* gets set nonzero when we see an arg */ for (;;) { if (getsym(buf, f) < 0) return NULL; if (*buf == ')' && (--inparen < 0)) { if (sawsomething) { /* if we've seen an arg */ pname[np] = plist; plist = word_alloc(""); np++; } break; } if (*buf == ';') { /* something weird */ return ABORTED; } sawsomething = 1; /* there's something in the arg. list */ if (*buf == ',' && inparen == 0) { pname[np] = plist; plist = word_alloc(""); np++; } else { addword(plist, buf); if (*buf == '(') inparen++; } } /* next, get the declarations after the function header */ inparen = 0; tlist = word_alloc(""); plist = word_alloc(""); tlistdone = 0; sawsomething = 0; for(;;) { if (getsym(buf, f) < 0) return NULL; /* handle a list like "int x,y,z" */ if (*buf == ',' && !inparen) { if (!sawsomething) return NULL; for (i = 0; i < np; i++) { if (!typed[i] && foundin(plist, pname[i])) { typed[i] = 1; word_free(pname[i]); pname[i] = word_append(tlist, plist); /* promote types */ if ( dopromote ) typefixhack(pname[i]); break; } } if (!tlistdone) { tlist = typelist(plist); tlistdone = 1; } word_free(plist); plist = word_alloc(""); } /* handle the end of a list */ else if (*buf == ';') { if (!sawsomething) return ABORTED; for (i = 0; i < np; i++) { if (!typed[i] && foundin(plist, pname[i])) { typed[i] = 1; word_free(pname[i]); pname[i] = word_append(tlist, plist); /* promote types */ if ( dopromote ) typefixhack(pname[i]); break; } } tlistdone = 0; word_free(tlist); word_free(plist); tlist = word_alloc(""); plist = word_alloc(""); } /* handle the beginning of the function */ else if (!strcmp(buf, "{}")) break; /* otherwise, throw the word into the list (except for "register") */ else if (strcmp(buf, "register")) { sawsomething = 1; addword(plist, buf); if (*buf == '(') inparen++; if (*buf == ')') inparen--; } } /* Now take the info we have and build a prototype list */ /* empty parameter list means "void" */ if (np == 0) return word_alloc("void"); plist = tlist = word_alloc(""); for (i = 0; i < np; i++) { /* If no type provided, make it an "int" */ if ( !(pname[i]->next) || (!(pname[i]->next->next)&&strcmp(pname[i]->next->string, "void"))) { addword(tlist, "int"); } while (tlist->next) tlist = tlist->next; tlist->next = pname[i]; if (i < np - 1) addword(tlist, ", "); } return plist; } /* * emit a function declaration. The attributes and name of the function * are in wlist; the parameters are in plist. */ void emit(wlist, plist, startline) Word *wlist, *plist; long startline; { Word *w; int count = 0; DEBUG("emit called\n"); if (donum) (void)printf("/*%8ld */ ", startline); for (w = wlist; w; w = w->next) { if ( w->string[0] == ':' ) return; /* C++ member function detected */ if (w->string[0]) count ++; } if (count < 2) (void)printf("int "); for (w = wlist; w; w = w->next) { (void)printf("%s", w->string); if (ISCSYM(w->string[0])) (void)printf(" "); } if (docond) (void)printf("PROTO(("); else (void)printf("( "); for (w = plist; w; w = w->next) { (void)printf("%s", w->string); if (ISCSYM(w->string[0])) (void)printf(" "); } if (docond) (void)printf("));\n"); else (void)printf(");\n"); } /* * get all the function declarations */ void getdecl(f) FILE *f; { Word *plist, *wlist = NULL; char buf[80]; int sawsomething; long startline; /* line where declaration started */ int oktoprint; again: word_free(wlist); wlist = word_alloc(""); sawsomething = 0; oktoprint = 1; for(;;) { DEBUG("main getdecl loop\n"); if (getsym(buf,f) < 0) { DEBUG("EOF in getdecl loop\n"); return; } /* try to guess when a declaration is not an external function definition */ if (!strcmp(buf, ",") || !strcmp(buf, "{}") || !strcmp(buf, "=") || !strcmp(buf, "typedef") || !strcmp(buf, "extern")) { (void)skipit(buf, f); goto again; } if (!dostatic && !strcmp(buf, "static")) { oktoprint = 0; } /* for the benefit of compilers that allow "inline" declarations */ if (!strcmp(buf, "inline") && !sawsomething) continue; if (!strcmp(buf, ";")) goto again; /* A left parenthesis *might* indicate a function definition */ if (!strcmp(buf, "(")) { startline = linenum; if (!sawsomething || !(plist = getparamlist(f))) { (void)skipit(buf, f); goto again; } if (plist == ABORTED) goto again; /* It seems to have been what we wanted */ if (oktoprint) emit(wlist, plist, startline); word_free(plist); goto again; } addword(wlist, buf); sawsomething = 1; } } void main(argc, argv) int argc; char *argv[]; { FILE *f; char *iobuf; char *title = "UNSPECIFIEDHEADERTITLE"; extern void Usage(); int opch; extern int Optind; extern char *Optarg; while ( ( opch = Getopt(argc,argv,"h:snpPD") ) != -1 ) switch ( opch ) { case 'h' : (void)strcpy(title, Optarg); break; case 's' : dostatic = true; break; case 'n' : donum = true; break; case 'p' : docond = true; break; case 'P' : dopromote = false; break; case 'D' : dodebug = true; break; default : Usage(argv[0]); exit(0); } /* ensw */ iobuf = malloc((unsigned)NEWBUFSIZ); (void)printf("#ifndef %s\n", title); (void)printf("#define %s\n", title); if (docond) { (void)printf("#ifdef __STDC__\n"); (void)printf("# define\tPROTO(s) s\n"); (void)printf("#else\n"); (void)printf("# define PROTO(s) ()\n"); (void)printf("#endif\n\n"); } if ( Optind > argc ) getdecl(stdin); else for ( ; Optind < argc; ++Optind ) { DEBUG("trying a new file\n"); if ( ( f = fopen(argv[Optind],"r") ) == (FILE *)0 ) { (void)fprintf(stderr,"%s: cannot open %s\n", argv[0], argv[Optind]); continue; } /* do the file operations here */ /* if (iobuf) (void)setvbuf(f, iobuf, _IOFBF, NEWBUFSIZ); /* */ if (dohead) (void)printf("\n/* %s */\n", argv[Optind]); linenum = 1; newline_seen = true; glastc = ' '; DEBUG("calling getdecl\n"); getdecl(f); DEBUG("back from getdecl\n"); DEBUG("back from fclose\n"); (void)fclose(f); } /* enfo */ if (docond) { (void)printf("\n#undef PROTO\n"); /* clean up namespace */ } (void)printf("\n#endif\n"); exit(EXIT_SUCCESS); } void Usage(progname) char *progname; { (void)fprintf(stderr,"Usage: %s [options][files ...]\n",progname); (void)fprintf(stderr, "\t-n: put line numbers of declarations as comments\n"); (void)fprintf(stderr, "\t-s: include declarations for static functions\n"); (void)fprintf(stderr, "\t-p: make header files readable by non-ANSI compilers\n"); (void)fprintf(stderr, "\t-P: don't promote any sc-specifiers\n"); (void)fprintf(stderr, "\t-h HeaderTitle: use HeaderTitle to title the header file\n"); (void)fprintf(stderr, "\t-D: operate on debug mode\n"); exit(EXIT_FAILURE); } #ifndef lint static char *scid = "s. manoharan edinburgh univ"; #endif #include<stdio.h> char *Optarg; int Optind; int Getopt(argc,argv,options) int argc; char **argv; char *options; { char *str, *ptr; char opch; char *Strchr(); static int flag = 0; static int Argc; static char **Argv; if ( flag == 0 ) { Argc = argc; Argv = argv; flag = 1; Optind = 1; } if ( Argc <= 1 ) return -1; if ( --Argc >= 1 ) { str = *++Argv; if (*str != '-') return -1; /* argument is not an option */ else { /* argument is an option */ if ( ( ptr = Strchr(options, opch = *++str) ) != (char *) 0 ) { ++Optind; Optarg = ++str; /* point to rest of argument if any */ if ( ( *++ptr == ':' ) && ( *Optarg == '\0' ) ) { if (--Argc <= 0) return '?'; Optarg = *++Argv; ++Optind; } return opch; } else if ( opch == '-' ) { /* end of options */ ++Optind; return -1; } else return '?'; } } return 0; /* this will never be reached */ } /* EnGetopt */ char *Strchr(s,c) char *s; char c; { while ( *s != '\0' ) { if ( *s == c ) return s; else ++s; } return ( (char *) 0 ); } /* EnStrchr */ @//E*O*F mkproto.c// chmod u=rw,g=,o= mkproto.c echo x - mkproto.h sed 's/^@//' > "mkproto.h" <<'@//E*O*F mkproto.h//' #ifdef __STDC__ # define PROTO(s) s #else # define PROTO(s) () #endif /* mkproto.c */ Word *word_alloc PROTO((char *s )); void word_free PROTO((Word *w )); int List_len PROTO((Word *w )); Word *word_append PROTO((Word *w1 , Word *w2 )); int foundin PROTO((Word *w1 , Word *w2 )); void addword PROTO((Word *w , char *s )); Word *typelist PROTO((Word *p )); void typefixhack PROTO((Word *w )); int ngetc PROTO((FILE *f )); int fnextch PROTO((FILE *f )); int nextch PROTO((FILE *f )); int getsym PROTO((char *buf , FILE *f )); int skipit PROTO((char *buf , FILE *f )); Word *getparamlist PROTO((FILE *f )); void emit PROTO((Word *wlist , Word *plist , long startline )); void getdecl PROTO((FILE *f )); void main PROTO((int argc , char **argv )); void Usage PROTO((void )); #undef PROTO @//E*O*F mkproto.h// chmod u=rw,g=,o= mkproto.h exit 0 ______________________ "And miles to go before I sleep." ______________________ Brad Appleton brad@ssd.csd.harris.com Harris Computer Systems uunet!hcx1!brad Fort Lauderdale, FL USA ~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~
utility@quiche.cs.mcgill.ca (Ronald BODKIN) (11/24/90)
In article <1906@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: >Right on! The function prototypes are just stupid. I shouldn't have to go: > extern gore *good(const char *vomit); >to get the functionality of type checking of function arguments. >The compiler and loader should do it. However, one prototype will allow you to automatically coerce things like ints to longs/floats/doubles or "near" pointers to "far" pointers, etc. Also, it is much faster to catch a prototype problem before linking a large application. Ron