From a0db846a9772ef82cf7163670e7a2fc109ec4b53 Mon Sep 17 00:00:00 2001 From: Greg King Date: Mon, 22 Jul 2019 09:05:01 -0400 Subject: [PATCH] Allowed old-style (K and R) function declarations to be fastcall. That lets them match old-style definitions. It avoids "Type conflict" error messages. It allows shorter function calls. Fixed the types of some variables in "test/ref/otccex.c". It avoids crashes on 64-bit Windows (32-bit Windows with 64-bit pointers). --- doc/cc65-intern.sgml | 12 ++++---- src/cc65/compile.c | 3 +- src/cc65/declare.c | 20 ++++++------- src/cc65/expr.c | 17 +++++++---- test/ref/Makefile | 10 ------- test/ref/otccex.c | 69 ++++++++++++++++++++++++-------------------- test/val/Makefile | 10 ------- 7 files changed, 66 insertions(+), 75 deletions(-) diff --git a/doc/cc65-intern.sgml b/doc/cc65-intern.sgml index ec6c48ca3..8e36578b5 100644 --- a/doc/cc65-intern.sgml +++ b/doc/cc65-intern.sgml @@ -42,7 +42,7 @@ The standard compliant variations Prologue, before the function call

@@ -61,8 +61,8 @@ The rightmost parameter will have the lowest address on the stack, and multi-byte parameters will have their least significant byte at the lower address. The @@ -108,8 +108,9 @@ The C-stack pointer - diff --git a/src/cc65/compile.c b/src/cc65/compile.c index bf9ada833..d914afb97 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -171,8 +171,9 @@ static void Parse (void) (CurTok.Tok != TOK_SEMI)) { FuncDesc* D = GetFuncDesc (Decl.Type); + if (D->Flags & FD_EMPTY) { - D->Flags = (D->Flags & ~(FD_EMPTY | FD_VARIADIC)) | FD_VOID_PARAM; + D->Flags = (D->Flags & ~FD_EMPTY) | FD_VOID_PARAM; } } diff --git a/src/cc65/declare.c b/src/cc65/declare.c index e3b5edfec..35ce5d0b2 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -1132,7 +1132,7 @@ static Type* ParamTypeCvt (Type* T) static void ParseOldStyleParamList (FuncDesc* F) -/* Parse an old style (K&R) parameter list */ +/* Parse an old-style (K&R) parameter list */ { /* Some fix point tokens that are used for error recovery */ static const token_t TokenList[] = { TOK_COMMA, TOK_RPAREN, TOK_SEMI }; @@ -1234,7 +1234,7 @@ static void ParseOldStyleParamList (FuncDesc* F) static void ParseAnsiParamList (FuncDesc* F) -/* Parse a new style (ANSI) parameter list */ +/* Parse a new-style (ANSI) parameter list */ { /* Parse params */ while (CurTok.Tok != TOK_RPAREN) { @@ -1330,32 +1330,30 @@ static FuncDesc* ParseFuncDecl (void) /* Check for several special parameter lists */ if (CurTok.Tok == TOK_RPAREN) { - /* Parameter list is empty */ - F->Flags |= (FD_EMPTY | FD_VARIADIC); + /* Parameter list is empty (K&R-style) */ + F->Flags |= FD_EMPTY; } else if (CurTok.Tok == TOK_VOID && NextTok.Tok == TOK_RPAREN) { /* Parameter list declared as void */ NextToken (); F->Flags |= FD_VOID_PARAM; } else if (CurTok.Tok == TOK_IDENT && (NextTok.Tok == TOK_COMMA || NextTok.Tok == TOK_RPAREN)) { - /* If the identifier is a typedef, we have a new style parameter list, - ** if it's some other identifier, it's an old style parameter list. + /* If the identifier is a typedef, we have a new-style parameter list; + ** if it's some other identifier, it's an old-style parameter list. */ Sym = FindSym (CurTok.Ident); if (Sym == 0 || !SymIsTypeDef (Sym)) { - /* Old style (K&R) function. */ + /* Old-style (K&R) function. */ F->Flags |= FD_OLDSTYLE; } } /* Parse params */ if ((F->Flags & FD_OLDSTYLE) == 0) { - - /* New style function */ + /* New-style function */ ParseAnsiParamList (F); - } else { - /* Old style function */ + /* Old-style function */ ParseOldStyleParamList (F); } diff --git a/src/cc65/expr.c b/src/cc65/expr.c index e6522f949..904c3af01 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -359,8 +359,8 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall) CHECK ((Param->Flags & SC_PARAM) != 0); } } else if (!Ellipsis) { - /* Too many arguments. Do we have an open param list? */ - if ((Func->Flags & FD_VARIADIC) == 0) { + /* Too many arguments. Do we have an open or empty param. list? */ + if ((Func->Flags & (FD_VARIADIC | FD_EMPTY)) == 0) { /* End of param list reached, no ellipsis */ Error ("Too many arguments in function call"); } @@ -401,8 +401,9 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall) Flags |= TypeOf (Expr.Type); /* If this is a fastcall function, don't push the last argument */ - if (ParamCount != Func->ParamCount || !IsFastcall) { + if ((CurTok.Tok == TOK_COMMA && NextTok.Tok != TOK_RPAREN) || !IsFastcall) { unsigned ArgSize = sizeofarg (Flags); + if (FrameSize > 0) { /* We have the space already allocated, store in the frame. ** Because of invalid type conversions (that have produced an @@ -472,8 +473,14 @@ static void FunctionCall (ExprDesc* Expr) /* Handle function pointers transparently */ IsFuncPtr = IsTypeFuncPtr (Expr->Type); if (IsFuncPtr) { - /* Check whether it's a fastcall function that has parameters */ - IsFastcall = (Func->Flags & FD_VARIADIC) == 0 && Func->ParamCount > 0 && + /* Check whether it's a fastcall function that has parameters. + ** Note: if a function is forward-declared in the old K & R style, then + ** it may be called with any number of arguments, even though its + ** parameter count is zero. Handle K & R functions as though there are + ** parameters. + */ + IsFastcall = (Func->Flags & FD_VARIADIC) == 0 && + (Func->ParamCount > 0 || (Func->Flags & FD_EMPTY)) && (AutoCDecl ? IsQualFastcall (Expr->Type + 1) : !IsQualCDecl (Expr->Type + 1)); diff --git a/test/ref/Makefile b/test/ref/Makefile index 3c2e582e4..5f0b86164 100644 --- a/test/ref/Makefile +++ b/test/ref/Makefile @@ -60,16 +60,6 @@ $(WORKDIR)/%.ref: %.c | $(WORKDIR) $(DIFF): ../bdiff.c | $(WORKDIR) $(CC) $(CFLAGS) -o $@ $< -# Some files have "K & R"-style syntax. Therefore, some forward -# function-declarations don't match the later function definitions. -# Those programs fail when fastcall is used; but, the cdecl calling convention -# tolerates those conflicts. Therefore, make their functions default to cdecl. -# -$(WORKDIR)/init.%.prg \ -$(WORKDIR)/switch.%.prg \ -$(WORKDIR)/yacc.%.prg \ -$(WORKDIR)/yaccdbg.%.prg: CC65FLAGS += -Wc --all-cdecl - # "yaccdbg.c" includes "yacc.c". # yaccdbg's built files must depend on both of them. # diff --git a/test/ref/otccex.c b/test/ref/otccex.c index 645078ef0..12a8b9bfc 100644 --- a/test/ref/otccex.c +++ b/test/ref/otccex.c @@ -8,31 +8,31 @@ /* * Sample OTCC C example. You can uncomment the first line and install - * otcc in /usr/local/bin to make otcc scripts ! + * otcc in /usr/local/bin to make otcc scripts ! */ /* Any preprocessor directive except #define are ignored. We put this include so that a standard C compiler can compile this code too. */ #include -#include /* defines are handled, but macro arguments cannot be given. No recursive defines are tolerated */ #define DEFAULT_BASE 10 #ifdef NO_IMPLICIT_FUNC_PROTOTYPES -help(char *name); +void help(char *name); #endif /* - * Only old style K&R prototypes are parsed. Only int arguments are + * Only old-style K&R prototypes are parsed. Only int arguments are * allowed (implicit types). - * + * * By benchmarking the execution time of this function (for example * for fib(35)), you'll notice that OTCC is quite fast because it - * generates native i386 machine code. + * generates native i386 machine code. */ -fib(n) +int fib(n) + int n; { printf("[fib(%d)]", n); if (n <= 2) @@ -42,12 +42,14 @@ fib(n) } /* Identifiers are parsed the same way as C: begins with letter or - '_', and then letters, '_' or digits */ + '_', and then letters, '_', or digits. */ long fact(n) + int n; { /* local variables can be declared. Only 'int' type is supported */ int i; long r; + r = 1; /* 'while' and 'for' loops are supported */ for(i=2;i<=n;i++) @@ -56,13 +58,15 @@ long fact(n) } /* Well, we could use printf, but it would be too easy */ -print_num(long n,int b) +void print_num(n, b) + long n; int b; { char *tab, *p, c; - /* Numbers can be entered in decimal, hexadecimal ('0x' prefix) and - octal ('0' prefix) */ - /* more complex programs use malloc */ - tab = malloc(0x100); + + /* Numbers can be entered in decimal, hexadecimal ('0x' prefix), and + octal ('0' prefix). */ + /* More complex programs use malloc(). */ + tab = malloc(0x100); p = tab; while (1) { c = n % b; @@ -80,29 +84,30 @@ print_num(long n,int b) } while (p != tab) { p--; - printf("%c", *(char *)p); + printf("%c", *p); } free(tab); } /* 'main' takes standard 'argc' and 'argv' parameters */ -mymain(int argc,char **argv) +int mymain(argc, argv) + int argc; char **argv; { - /* no local name space is supported, but local variables ARE + /* No local name space is supported, but local variables ARE supported. As long as you do not use a globally defined - variable name as local variable (which is a bad habbit), you - won't have any problem */ - int s, n, f, base; - - + variable name as a local variable (which is a bad habit), you + won't have any problems. */ + size_t s, f; + int n, base; + /* && and || operator have the same semantics as C (left to right evaluation and early exit) */ if (argc != 2 && argc != 3) { /* '*' operator is supported with explicit casting to 'int *', - 'char *' or 'int (*)()' (function pointer). Of course, 'int' - are supposed to be used as pointers too. */ - s = *(int *)argv; - help(s); + 'char *', or 'int (*)()' (function pointer). Of course, 'int' + are supposed to be used as pointers, too. */ + s = *(size_t *)argv; + help((char *)s); return 1; } /* Any libc function can be used because OTCC uses dynamic linking */ @@ -125,15 +130,15 @@ mymain(int argc,char **argv) printf("Overflow"); } else { /* why not using a function pointer ? */ - f = &fact; - print_num((*(long (*)(int))f)(n), base); + f = (size_t)&fact; + print_num((*(long (*)())f)(n), base); } printf("\n"); return 0; } /* functions can be used before being defined */ -help(char *name) +void help(char *name) { printf("usage: %s n [base]\n", name); printf("Compute fib(n) and fact(n) and output the result in base 'base'\n"); @@ -142,9 +147,9 @@ help(char *name) int main(void) { char *argv[3]; - argv[0]=""; + + argv[0]="otccex"; argv[1]="10"; /* n */ argv[2]="8"; /* base */ - mymain(3, argv); - return 0; -} \ No newline at end of file + return mymain(3, argv); +} diff --git a/test/val/Makefile b/test/val/Makefile index fe194d892..df1d314e4 100644 --- a/test/val/Makefile +++ b/test/val/Makefile @@ -44,16 +44,6 @@ all: $(TESTS) $(WORKDIR): $(call MKDIR,$(WORKDIR)) -# Some files have "K & R"-style syntax. Therefore, some forward -# function-declarations don't match the later function definitions. -# Those programs fail when fastcall is used; but, the cdecl calling convention -# tolerates those conflicts. Therefore, make their functions default to cdecl. -# -$(WORKDIR)/cq4.%.prg \ -$(WORKDIR)/cq71.%.prg \ -$(WORKDIR)/cq81.%.prg \ -$(WORKDIR)/cq84.%.prg: CC65FLAGS += -Wc --all-cdecl - define PRG_template $(WORKDIR)/%.$1.$2.prg: %.c | $(WORKDIR)