diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-10-07 17:58:53 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-10-07 17:58:53 +0000 |
commit | 14b353bdf99a61b29314822d06fff3f7250019ac (patch) | |
tree | cfb9b82ab66c64756933986a1d66b0b133819ab4 /usr.bin/pcc/ccom | |
parent | 71267fa7f73e6e874cf9cb489551cb44ead37aba (diff) |
reorg pcc tree; requested by and ok deraadt@; ok ragge@
Diffstat (limited to 'usr.bin/pcc/ccom')
-rw-r--r-- | usr.bin/pcc/ccom/Makefile | 9 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/Makefile.inc | 45 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/ccom.1 | 167 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/cgram.y | 1403 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/gcc_compat.c | 126 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/init.c | 968 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/inline.c | 209 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/main.c | 317 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/optim.c | 355 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/pass1.h | 394 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/pftn.c | 2676 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/scan.l | 467 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/stabs.c | 374 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/symtabs.c | 356 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/trees.c | 2466 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/vax/Makefile | 3 | ||||
-rw-r--r-- | usr.bin/pcc/ccom/x86/Makefile | 3 |
17 files changed, 10338 insertions, 0 deletions
diff --git a/usr.bin/pcc/ccom/Makefile b/usr.bin/pcc/ccom/Makefile new file mode 100644 index 00000000000..52406f7ac61 --- /dev/null +++ b/usr.bin/pcc/ccom/Makefile @@ -0,0 +1,9 @@ +# $OpenBSD: Makefile,v 1.1 2007/10/07 17:58:51 otto Exp $ +# +# Makefile for the ccom part of pcc. +# + +SUBDIR+= x86 +#SUBDIR+= vax + +.include <bsd.subdir.mk> diff --git a/usr.bin/pcc/ccom/Makefile.inc b/usr.bin/pcc/ccom/Makefile.inc new file mode 100644 index 00000000000..c08dff221d9 --- /dev/null +++ b/usr.bin/pcc/ccom/Makefile.inc @@ -0,0 +1,45 @@ +# $OpenBSD: Makefile.inc,v 1.1 2007/10/07 17:58:51 otto Exp $ +# +# Makefile for the ccom part of pcc. +# + +PROG= ccom_${TARGMACH} +MAN= ccom.1 + +PREFIX= /usr/local +BINDIR= ${PREFIX}/libexec +MANDIR= ${PREFIX}/man/man +TARGOS= openbsd +CLEANFILES= external.h external.c mkext + +CFLAGS+= -DPCC_DEBUG -DGCC_COMPAT +CFLAGS+= -Wall -Wmissing-prototypes -Wstrict-prototypes -Werror +CFLAGS+= -DLIBEXECDIR=\"${PREFIX}/libexec\" +CPPFLAGS+= -I. -I${.CURDIR}/.. -I${.CURDIR} -I${.CURDIR}/../../mip +CPPFLAGS+= -I${.CURDIR}/../../${TARGMACH} +CPPFLAGS+= -I${.CURDIR}/../.. + +.PATH: ${.CURDIR}/../../${TARGMACH} +.PATH: ${.CURDIR}/../../mip +.PATH: ${.CURDIR}/.. + +SRCS=optim.c pftn.c scan.l trees.c cgram.y inline.c symtabs.c \ + gcc_compat.c init.c local.c code.c stabs.c match.c reader.c optim2.c \ + regs.c local2.c order.c table.c common.c main.c external.c + +cgram.c: cgram.y + $(YACC) $(YFLAGS) -d $< + mv y.tab.c cgram.c + mv y.tab.h cgram.h + +mkext: mkext.c table.c common.c + $(CC) $(CPPFLAGS) $(CFLAGS) -DMKEXT -o mkext \ + ${.CURDIR}/../../mip/mkext.c \ + ${.CURDIR}/../../${TARGMACH}/table.c \ + ${.CURDIR}/../../mip/common.c + +external.h external.c: mkext + ./mkext + +cleandepend: + rm -f .depend ${.CURDIR}/tags cgram.h diff --git a/usr.bin/pcc/ccom/ccom.1 b/usr.bin/pcc/ccom/ccom.1 new file mode 100644 index 00000000000..2ad56676fab --- /dev/null +++ b/usr.bin/pcc/ccom/ccom.1 @@ -0,0 +1,167 @@ +.\" $Id: ccom.1,v 1.1 2007/10/07 17:58:51 otto Exp $ +.\" $NetBSD$ +.\" $OpenBSD: ccom.1,v 1.1 2007/10/07 17:58:51 otto Exp $ +."\ +.\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net> +.\" Permission to use, copy, modify, and/or distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM +.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND +.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +.\" THIS SOFTWARE. +.Dd September 14, 2007 +.Dt ccom 1 +.Os +.Sh NAME +.Nm ccom +.Nd C compiler +.Sh SYNOPSIS +.Nm +.Op Fl gs +.Op Fl W Ar flags +.Op Fl X Ar flags +.Op Fl x Ar optimizations +.Op Fl Z Ar flags +.Op infile +.Op outfile +.Pp +.Sh DESCRIPTION +The +.Nm +utility provides a C compiler. +The frontend is usually +.Xr pcc 1 . +It is \fBnot\fR intended to be run directly. +.Pp +.Nm +reads the C source from +.Ar infile +or standard input and writes the assembler source +to +.Ar outfile +or to standard output. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl g +Enable debugging. +.\" built into binary, explain stabs? +.It Fl s +Print statistics to standard error when complete. +This includes: +name table entries, name string size, permanent allocated memory, +temporary allocated memory, lost memory, argument list unions, +dimension/function unions, struct/union/enum blocks, inline node count, +inline control blocks, and permanent symtab entries. +.\" TODO: explain units for above? +.It Fl v +Display version. +.It Fl W Ar flags +Report warnings. +(Do some basic checks.) +NOTE! These are subject to change RSN! +.Ar flags +is one or more of the following: +.Bl -tag -width Ds +.It Sy implicit +Implies +.Sy implicit-function-declaration +and +.Sy implicit-int . +.It Sy implicit-function-declaration +Report if no prototype for function. +.It Sy implicit-int +TODO +.It Sy missing-prototypes +TODO +.It Sy strict-prototypes +TODO +.El +.\" +.It Fl X Ar flags +C specific debugging where +.Ar flags +is one or more of the following: +.Bl -tag -width Ds +.It Sy b +Building of parse trees +.It Sy d +Declarations (multiple +.Sy d +flags gives more output) +.It Sy e +Pass1 trees at exit +.It Sy i +Initializations +.It Sy t +Type conversions +.It Sy x +Target-specific flag, used in machine-dependent code +.El +.\" +.It Fl x Ar optimizations +.Ar optimizations +is one or more of the following: +.\" TODO: reword this, since multiple terms don't go with one -x switch?? +.Bl -tag -width deljumps +.It Sy deljumps +Delete redundant jumps and dead code. +.It Sy ssa +Convert statements into SSA form for optimization. Not yet finished. +.It Sy tailcall +Currently not implemented. +.It Sy temps +Setting this flag allows variables to be put into registers, for further +optimization by the register allocator. +.El +.\" +.It Fl Z Ar flags +Code generator (pass2) specific debugging where +.Ar flags +is one or more of the following: +.Bl -tag -width Ds +.It Sy e +Trees when entering pass2 +.It Sy f +Instruction matcher, may provide much output +.It Sy o +Instruction generator +.It Sy r +Register allocator +.It Sy s +Shape matching in instruction generator +.It Sy t +Type matching in instruction generator +.It Sy u +Sethi-Ullman computations +.It Sy x +Target-specific flag, used in machine-dependent code +.El +.El +.Sh SEE ALSO +.Xr as 1 , +.Xr cpp 1 , +.Xr pcc 1 +.Sh HISTORY +The +.Nm +compiler is based on the original Portable C Compiler by S. C. +Johnson, written in the late 70's. +Even though much of the compiler has been rewritten, some of the +basics still remain. +About 50% of the frontend code and 80% of the backend code has been +rewritten. +Most is written by Anders Magnusson, with the exception of +the data-flow analysis part and the SSA conversion code which is +written by Peter A Jonsson, and the Mips port that were written as +part of a project by undergraduate students at Lulea University of +Technology. +.Pp +This product includes software developed or owned by Caldera +International, Inc. diff --git a/usr.bin/pcc/ccom/cgram.y b/usr.bin/pcc/ccom/cgram.y new file mode 100644 index 00000000000..d77193c2c8e --- /dev/null +++ b/usr.bin/pcc/ccom/cgram.y @@ -0,0 +1,1403 @@ +/* $OpenBSD: cgram.y,v 1.1 2007/10/07 17:58:51 otto Exp $ */ + +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Comments for this grammar file. Ragge 021123 + * + * ANSI support required rewrite of the function header and declaration + * rules almost totally. + * + * The lex/yacc shared keywords are now split from the keywords used + * in the rest of the compiler, to simplify use of other frontends. + */ + +/* + * At last count, there were 3 shift/reduce and no reduce/reduce conflicts + * Two was funct_idn and the third was "dangling else". + */ + +/* + * Token used in C lex/yacc communications. + */ +%token C_WSTRING /* a wide string constant */ +%token C_STRING /* a string constant */ +%token C_ICON /* an integer constant */ +%token C_FCON /* a floating point constant */ +%token C_NAME /* an identifier */ +%token C_TYPENAME /* a typedef'd name */ +%token C_ANDAND /* && */ +%token C_OROR /* || */ +%token C_GOTO /* unconditional goto */ +%token C_RETURN /* return from function */ +%token C_TYPE /* a type */ +%token C_CLASS /* a storage class */ +%token C_ASOP /* assignment ops */ +%token C_RELOP /* <=, <, >=, > */ +%token C_EQUOP /* ==, != */ +%token C_DIVOP /* /, % */ +%token C_SHIFTOP /* <<, >> */ +%token C_INCOP /* ++, -- */ +%token C_UNOP /* !, ~ */ +%token C_STROP /* ., -> */ +%token C_STRUCT +%token C_IF +%token C_ELSE +%token C_SWITCH +%token C_BREAK +%token C_CONTINUE +%token C_WHILE +%token C_DO +%token C_FOR +%token C_DEFAULT +%token C_CASE +%token C_SIZEOF +%token C_ENUM +%token C_ELLIPSIS +%token C_QUALIFIER +%token C_FUNSPEC +%token C_ASM + +/* + * Precedence + */ +%left ',' +%right '=' C_ASOP +%right '?' ':' +%left C_OROR +%left C_ANDAND +%left '|' +%left '^' +%left '&' +%left C_EQUOP +%left C_RELOP +%left C_SHIFTOP +%left '+' '-' +%left '*' C_DIVOP +%right C_UNOP +%right C_INCOP C_SIZEOF +%left '[' '(' C_STROP +%{ +# include "pass1.h" +# include <stdarg.h> +# include <string.h> + +static int fun_inline; /* Reading an inline function */ +int oldstyle; /* Current function being defined */ +int noretype; +static struct symtab *xnf; +#ifdef GCC_COMPAT +char *renname; /* for renaming of variables */ +#endif + + +static NODE *bdty(int op, ...); +static void fend(void); +static void fundef(NODE *tp, NODE *p); +static void olddecl(NODE *p); +static struct symtab *init_declarator(NODE *tn, NODE *p, int assign); +static void resetbc(int mask); +static void swend(void); +static void addcase(NODE *p); +static void adddef(void); +static void savebc(void); +static void swstart(int); +static NODE * structref(NODE *p, int f, char *name); +static char *mkpstr(char *str); +static struct symtab *clbrace(NODE *); + +/* + * State for saving current switch state (when nested switches). + */ +struct savbc { + struct savbc *next; + int brklab; + int contlab; + int flostat; + int swx; +} *savbc, *savctx; + +%} + +%union { + int intval; + NODE *nodep; + struct symtab *symp; + struct rstack *rp; + char *strp; +} + + /* define types */ +%start ext_def_list + +%type <intval> con_e ifelprefix ifprefix whprefix forprefix doprefix switchpart + type_qualifier_list +%type <nodep> e .e term enum_dcl struct_dcl cast_type funct_idn declarator + direct_declarator elist type_specifier merge_attribs + parameter_declaration abstract_declarator initializer + parameter_type_list parameter_list addrlbl + declaration_specifiers pointer direct_abstract_declarator + specifier_qualifier_list merge_specifiers nocon_e + identifier_list arg_param_list arg_declaration arg_dcl_list + designator_list designator +%type <strp> string wstring C_STRING C_WSTRING +%type <rp> enum_head str_head +%type <symp> xnfdeclarator clbrace + +%type <intval> C_CLASS C_STRUCT C_RELOP C_DIVOP C_SHIFTOP + C_ANDAND C_OROR C_STROP C_INCOP C_UNOP C_ASOP C_EQUOP +%type <nodep> C_TYPE C_QUALIFIER C_ICON C_FCON +%type <strp> C_NAME C_TYPENAME + +%% + +ext_def_list: ext_def_list external_def + | { ftnend(); } + ; + +external_def: function_definition { blevel = 0; } + | declaration { blevel = 0; symclear(0); } + | asmstatement ';' + | ';' + | error { blevel = 0; } + ; + +function_definition: + /* Ansi (or K&R header without parameter types) */ + declaration_specifiers declarator { + fundef($1, $2); + } compoundstmt { fend(); } + /* Same as above but without declaring function type */ + | declarator { + noretype = 1; + fundef(mkty(INT, 0, MKSUE(INT)), $1); + } compoundstmt { fend(); noretype = 0; } + /* K&R function without type declaration */ + | declarator { + noretype = 1; + if (oldstyle == 0) + uerror("bad declaration in ansi function"); + fundef(mkty(INT, 0, MKSUE(INT)), $1); + } arg_dcl_list compoundstmt { fend(); noretype = 0; } + /* K&R function with type declaration */ + | declaration_specifiers declarator { + if (oldstyle == 0) + uerror("bad declaration in ansi function"); + fundef($1, $2); + } arg_dcl_list compoundstmt { fend(); } + ; + +/* + * Returns a node pointer or NULL, if no types at all given. + * Type trees are checked for correctness and merged into one + * type node in typenode(). + */ +declaration_specifiers: + merge_attribs { $$ = typenode($1); } + ; + +merge_attribs: C_CLASS { $$ = block(CLASS, NIL, NIL, $1, 0, 0); } + | C_CLASS merge_attribs { $$ = block(CLASS, $2, NIL, $1,0,0);} + | type_specifier { $$ = $1; } + | type_specifier merge_attribs { $1->n_left = $2; $$ = $1; } + | C_QUALIFIER { $$ = $1; } + | C_QUALIFIER merge_attribs { $1->n_left = $2; $$ = $1; } + | function_specifiers { $$ = NIL; } + | function_specifiers merge_attribs { $$ = $2; } + ; + +function_specifiers: + C_FUNSPEC { + if (fun_inline) + uerror("too many inline"); + fun_inline = 1; + } + ; + +type_specifier: C_TYPE { $$ = $1; } + | C_TYPENAME { + struct symtab *sp = lookup($1, 0); + $$ = mkty(sp->stype, sp->sdf, sp->ssue); + $$->n_sp = sp; + } + | struct_dcl { $$ = $1; } + | enum_dcl { $$ = $1; } + ; + +/* + * Adds a pointer list to front of the declarators. + * Note the UMUL right node pointer usage. + */ +declarator: pointer direct_declarator { + $$ = $1; $1->n_right->n_left = $2; + } + | direct_declarator { $$ = $1; } + ; + +/* + * Return an UMUL node type linked list of indirections. + */ +pointer: '*' { $$ = bdty(UMUL, NIL); $$->n_right = $$; } + | '*' type_qualifier_list { + $$ = bdty(UMUL, NIL); + $$->n_qual = $2; + $$->n_right = $$; + } + | '*' pointer { + $$ = bdty(UMUL, $2); + $$->n_right = $2->n_right; + } + | '*' type_qualifier_list pointer { + $$ = bdty(UMUL, $3); + $$->n_qual = $2; + $$->n_right = $3->n_right; + } + ; + +type_qualifier_list: + C_QUALIFIER { $$ = $1->n_type; nfree($1); } + | type_qualifier_list C_QUALIFIER { + $$ = $1 | $2->n_type; nfree($2); + } + ; + +/* + * Sets up a function declarator. The call node will have its parameters + * connected to its right node pointer. + */ +direct_declarator: C_NAME { $$ = bdty(NAME, $1); } + | '(' declarator ')' { $$ = $2; } + | direct_declarator '[' nocon_e ']' { + $$ = block(LB, $1, $3, INT, 0, MKSUE(INT)); + } + | direct_declarator '[' ']' { $$ = bdty(LB, $1, 0); } + | direct_declarator '(' notype parameter_type_list ')' { + $$ = bdty(CALL, $1, $4); + } + | direct_declarator '(' notype identifier_list ')' { + $$ = bdty(CALL, $1, $4); + if (blevel != 0) + uerror("function declaration in bad context"); + oldstyle = 1; + } + | direct_declarator '(' ')' { $$ = bdty(UCALL, $1); } + ; + +notype: { /* extern int notype, doproto; notype = 0; doproto=1; printf("notype\n"); */ } + ; + +identifier_list: C_NAME { $$ = bdty(NAME, $1); $$->n_type = FARG; } + | identifier_list ',' C_NAME { + $$ = bdty(NAME, $3); + $$->n_type = FARG; + $$ = block(CM, $1, $$, 0, 0, 0); + } + ; + +/* + * Returns as parameter_list, but can add an additional ELLIPSIS node. + * Calls revert() to get the parameter list in the forward order. + */ +parameter_type_list: + parameter_list { $$ = $1; } + | parameter_list ',' C_ELLIPSIS { + $$ = block(CM, $1, block(ELLIPSIS, NIL, NIL, 0, 0, 0), + 0, 0, 0); + } + ; + +/* + * Returns a linked lists of nodes of op CM with parameters on + * its right and additional CM nodes of its left pointer. + * No CM nodes if only one parameter. + */ +parameter_list: parameter_declaration { $$ = $1; } + | parameter_list ',' parameter_declaration { + $$ = block(CM, $1, $3, 0, 0, 0); + } + ; + +/* + * Returns a node pointer to the declaration. + */ +parameter_declaration: + declaration_specifiers declarator { + $$ = tymerge($1, $2); + nfree($1); + } + | declaration_specifiers abstract_declarator { + $$ = tymerge($1, $2); + nfree($1); + } + | declaration_specifiers { + $$ = tymerge($1, bdty(NAME, NULL)); + nfree($1); + } + ; + +abstract_declarator: + pointer { $$ = $1; $1->n_right->n_left = bdty(NAME, NULL); } + | direct_abstract_declarator { $$ = $1; } + | pointer direct_abstract_declarator { + $$ = $1; $1->n_right->n_left = $2; + } + ; + +direct_abstract_declarator: + '(' abstract_declarator ')' { $$ = $2; } + | '[' ']' { $$ = bdty(LB, bdty(NAME, NULL), 0); } + | '[' con_e ']' { $$ = bdty(LB, bdty(NAME, NULL), $2); } + | direct_abstract_declarator '[' ']' { $$ = bdty(LB, $1, 0); } + | direct_abstract_declarator '[' con_e ']' { + $$ = bdty(LB, $1, $3); + } + | '(' ')' { $$ = bdty(UCALL, bdty(NAME, NULL)); } + | '(' notype parameter_type_list ')' { + $$ = bdty(CALL, bdty(NAME, NULL), $3); + } + | direct_abstract_declarator '(' ')' { + $$ = bdty(UCALL, $1); + } + | direct_abstract_declarator '(' notype parameter_type_list ')' { + $$ = bdty(CALL, $1, $4); + } + ; + +/* + * K&R arg declaration, between ) and { + */ +arg_dcl_list: arg_declaration + | arg_dcl_list arg_declaration + ; + + +arg_declaration: declaration_specifiers arg_param_list ';' { + nfree($1); + } + ; + +arg_param_list: declarator { olddecl(tymerge($<nodep>0, $1)); } + | arg_param_list ',' declarator { + olddecl(tymerge($<nodep>0, $3)); + } + ; + +/* + * Declarations in beginning of blocks. + */ +declaration_list: declaration + | declaration_list declaration + ; + +/* + * Here starts the old YACC code. + */ + +stmt_list: stmt_list statement + | { bccode(); } + ; + +/* + * Variables are declared in init_declarator. + */ +declaration: declaration_specifiers ';' { nfree($1); goto inl; } + | declaration_specifiers init_declarator_list ';' { + nfree($1); + inl: + fun_inline = 0; + } + ; + +/* + * Normal declaration of variables. curtype contains the current type node. + * Returns nothing, variables are declared in init_declarator. + */ +init_declarator_list: + init_declarator + | init_declarator_list ',' { $<nodep>$ = $<nodep>0; } init_declarator + ; + +enum_dcl: enum_head '{' moe_list optcomma '}' { $$ = dclstruct($1); } + | C_ENUM C_NAME { $$ = rstruct($2,0); } + | C_ENUM C_TYPENAME { $$ = rstruct($2,0); } + ; + +enum_head: C_ENUM { $$ = bstruct(NULL,0); } + | C_ENUM C_NAME { $$ = bstruct($2,0); } + | C_ENUM C_TYPENAME { $$ = bstruct($2,0); } + ; + +moe_list: moe + | moe_list ',' moe + ; + +moe: C_NAME { moedef( $1 ); } + | C_NAME '=' con_e { strucoff = $3; moedef( $1 ); } + ; + +struct_dcl: str_head '{' struct_dcl_list '}' { $$ = dclstruct($1); } + | C_STRUCT C_NAME { $$ = rstruct($2,$1); } + | C_STRUCT C_TYPENAME { $$ = rstruct($2,$1); } + | str_head '{' '}' { +#ifndef GCC_COMPAT + werror("gcc extension"); +#endif + $$ = dclstruct($1); + } + ; + +str_head: C_STRUCT { $$ = bstruct(NULL, $1); } + | C_STRUCT C_NAME { $$ = bstruct($2,$1); } + | C_STRUCT C_TYPENAME { $$ = bstruct($2,$1); } + ; + +struct_dcl_list: struct_declaration + | struct_dcl_list struct_declaration + ; + +struct_declaration: + specifier_qualifier_list struct_declarator_list ';' { + nfree($1); + } + ; + +specifier_qualifier_list: + merge_specifiers { $$ = typenode($1); } + ; + +merge_specifiers: type_specifier merge_specifiers { $1->n_left = $2;$$ = $1; } + | type_specifier { $$ = $1; } + | C_QUALIFIER merge_specifiers { $1->n_left = $2; $$ = $1; } + | C_QUALIFIER { $$ = $1; } + ; + +struct_declarator_list: + struct_declarator { } + | struct_declarator_list ',' { $<nodep>$=$<nodep>0; } + struct_declarator { } + ; + +struct_declarator: declarator { + tymerge($<nodep>0, $1); + $1->n_sp = getsymtab((char *)$1->n_sp, SMOSNAME); /* XXX */ + defid($1, $<nodep>0->n_lval); + nfree($1); + } + | ':' con_e { + if (!(instruct&INSTRUCT)) + uerror( "field outside of structure" ); + falloc(NULL, $2, -1, $<nodep>0); + } + | declarator ':' con_e { + if (!(instruct&INSTRUCT)) + uerror( "field outside of structure" ); + if( $3<0 || $3 >= FIELD ){ + uerror( "illegal field size" ); + $3 = 1; + } + if ($1->n_op == NAME) { + tymerge($<nodep>0, $1); + $1->n_sp = getsymtab((char *)$1->n_sp,SMOSNAME); + defid($1, FIELD|$3); + nfree($1); + } else + uerror("illegal declarator"); + } + ; + + /* always preceeded by attributes */ +xnfdeclarator: declarator { $$ = xnf = init_declarator($<nodep>0, $1, 1); } + ; + +/* + * Handles declarations and assignments. + * Returns nothing. + */ +init_declarator: declarator { init_declarator($<nodep>0, $1, 0); } + | declarator C_ASM '(' string ')' { +#ifdef GCC_COMPAT + renname = $4; + init_declarator($<nodep>0, $1, 0); +#else + werror("gcc extension"); + init_declarator($<nodep>0, $1, 0); +#endif + } + | xnfdeclarator '=' e { simpleinit($1, $3); xnf = NULL; } + | xnfdeclarator '=' begbr init_list optcomma '}' { + endinit(); + xnf = NULL; + } + | xnfdeclarator '=' addrlbl { simpleinit($1, $3); xnf = NULL; } + ; + +begbr: '{' { beginit($<symp>-1); } + ; + +initializer: e %prec ',' { $$ = $1; } + | addrlbl { $$ = $1; } + | ibrace init_list optcomma '}' { $$ = NULL; } + ; + +init_list: designation initializer { asginit($2); } + | init_list ',' designation initializer { asginit($4); } + ; + +designation: designator_list '=' { desinit($1); } + | { /* empty */ } + ; + +designator_list: designator { $$ = $1; } + | designator_list designator { $$ = $2; $$->n_left = $1; } + ; + +designator: '[' con_e ']' { $$ = bdty(LB, NULL, $2); } + | C_STROP C_NAME { $$ = bdty(NAME, $2); } + ; + +optcomma : /* VOID */ + | ',' + ; + +ibrace: '{' { ilbrace(); } + ; + +/* STATEMENTS */ + +compoundstmt: begin declaration_list stmt_list '}' { +#ifdef STABS + if (gflag && blevel > 2) + stabs_rbrac(blevel); +#endif + --blevel; + if( blevel == 1 ) + blevel = 0; + symclear(blevel); /* Clean ut the symbol table */ + if (autooff > maxautooff) + maxautooff = autooff; + autooff = savctx->contlab; + savctx = savctx->next; + } + | begin stmt_list '}' { +#ifdef STABS + if (gflag && blevel > 2) + stabs_rbrac(blevel); +#endif + --blevel; + if( blevel == 1 ) + blevel = 0; + symclear(blevel); /* Clean ut the symbol table */ + if (autooff > maxautooff) + maxautooff = autooff; + autooff = savctx->contlab; + savctx = savctx->next; + } + ; + +begin: '{' { + struct savbc *bc = tmpalloc(sizeof(struct savbc)); + if (blevel == 1) { +#ifdef STABS + if (gflag) + stabs_line(lineno); +#endif + dclargs(); + } +#ifdef STABS + if (gflag && blevel > 1) + stabs_lbrac(blevel+1); +#endif + ++blevel; + oldstyle = 0; + bc->contlab = autooff; + bc->next = savctx; + savctx = bc; + } + ; + +statement: e ';' { ecomp( $1 ); } + | compoundstmt + | ifprefix statement { plabel($1); reached = 1; } + | ifelprefix statement { + if ($1 != NOLAB) { + plabel( $1); + reached = 1; + } + } + | whprefix statement { + branch(contlab); + plabel( brklab ); + if( (flostat&FBRK) || !(flostat&FLOOP)) + reached = 1; + else + reached = 0; + resetbc(0); + } + | doprefix statement C_WHILE '(' e ')' ';' { + plabel(contlab); + if (flostat & FCONT) + reached = 1; + if (reached) + cbranch($5, bcon($1)); + else + tfree($5); + plabel( brklab); + reached = 1; + resetbc(0); + } + | forprefix .e ')' statement + { plabel( contlab ); + if( flostat&FCONT ) reached = 1; + if( $2 ) ecomp( $2 ); + branch($1); + plabel( brklab ); + if( (flostat&FBRK) || !(flostat&FLOOP) ) reached = 1; + else reached = 0; + resetbc(0); + } + | switchpart statement + { if( reached ) branch( brklab ); + plabel( $1 ); + swend(); + plabel( brklab); + if( (flostat&FBRK) || !(flostat&FDEF) ) reached = 1; + resetbc(FCONT); + } + | C_BREAK ';' { + if (brklab == NOLAB) + uerror("illegal break"); + else if (reached) + branch(brklab); + flostat |= FBRK; + reached = 0; + } + | C_CONTINUE ';' { + if (contlab == NOLAB) + uerror("illegal continue"); + else + branch(contlab); + flostat |= FCONT; + goto rch; + } + | C_RETURN ';' { + branch(retlab); + if (cftnsp->stype != VOID && noretype && + cftnsp->stype != VOID+FTN) + uerror("return value required"); + rch: + if (!reached) + werror( "statement is not reached"); + reached = 0; + } + | C_RETURN e ';' { + register NODE *temp; + + spname = cftnsp; + temp = buildtree( NAME, NIL, NIL ); + temp->n_type = DECREF(temp->n_type); + temp = buildtree(RETURN, temp, $2); + + if (temp->n_type == VOID) + ecomp(temp->n_right); + else + ecomp(buildtree(FORCE, temp->n_right, NIL)); + nfree(temp->n_left); + nfree(temp); + branch(retlab); + reached = 0; + } + | C_GOTO C_NAME ';' { gotolabel($2); goto rch; } + | C_GOTO '*' e ';' { + ecomp(block(GOTO, $3, NIL, INT, 0, 0)); + } + | asmstatement ';' + | ';' + | error ';' + | error '}' + | label statement + ; + +asmstatement: C_ASM '(' string ')' { send_passt(IP_ASM, mkpstr($3)); } + ; + +label: C_NAME ':' { deflabel($1); reached = 1; } + | C_CASE e ':' { addcase($2); reached = 1; } + | C_DEFAULT ':' { reached = 1; adddef(); flostat |= FDEF; } + ; + +doprefix: C_DO { + savebc(); + if (!reached) + werror("loop not entered at top"); + brklab = getlab(); + contlab = getlab(); + plabel( $$ = getlab()); + reached = 1; + } + ; +ifprefix: C_IF '(' e ')' { + cbranch(buildtree(NOT, $3, NIL), bcon($$ = getlab())); + reached = 1; + } + ; +ifelprefix: ifprefix statement C_ELSE { + if (reached) + branch($$ = getlab()); + else + $$ = NOLAB; + plabel( $1); + reached = 1; + } + ; + +whprefix: C_WHILE '(' e ')' { + savebc(); + if (!reached) + werror("loop not entered at top"); + if ($3->n_op == ICON && $3->n_lval != 0) + flostat = FLOOP; + plabel( contlab = getlab()); + reached = 1; + brklab = getlab(); + if (flostat == FLOOP) + tfree($3); + else + cbranch(buildtree(NOT, $3, NIL), bcon(brklab)); + } + ; +forprefix: C_FOR '(' .e ';' .e ';' { + if ($3) + ecomp($3); + else if (!reached) + werror("loop not entered at top"); + savebc(); + contlab = getlab(); + brklab = getlab(); + plabel( $$ = getlab()); + reached = 1; + if ($5) + cbranch(buildtree(NOT, $5, NIL), bcon(brklab)); + else + flostat |= FLOOP; + } + ; +switchpart: C_SWITCH '(' e ')' { + NODE *p; + int num; + + savebc(); + brklab = getlab(); + if ($3->n_type != INT) { + /* must cast to integer */ + p = block(NAME, NIL, NIL, INT, 0, MKSUE(INT)); + p = buildtree(CAST, p, $3); + $3 = p->n_right; + nfree(p->n_left); + nfree(p); + } +// ecomp( buildtree( FORCE, $3, NIL ) ); + p = tempnode(0, INT, 0, MKSUE(INT)); + num = p->n_lval; + ecomp(buildtree(ASSIGN, p, $3)); + branch( $$ = getlab()); + swstart(num); + reached = 0; + } + ; +/* EXPRESSIONS */ +con_e: { $<intval>$=instruct; instruct=0; } e %prec ',' { + $$ = icons( $2 ); + instruct=$<intval>1; + } + ; + +nocon_e: { $<intval>$=instruct; instruct=0; } e %prec ',' { + instruct=$<intval>1; + $$ = $2; + } + ; + +.e: e + | { $$=0; } + ; + +elist: e %prec ',' + | elist ',' e { $$ = buildtree(CM, $1, $3); } + | elist ',' cast_type { /* hack for stdarg */ + $3->n_op = TYPE; + $$ = buildtree(CM, $1, $3); + } + ; + +/* + * Precedence order of operators. + */ +e: e ',' e { $$ = buildtree(COMOP, $1, $3); } + | e '=' e { $$ = buildtree(ASSIGN, $1, $3); } + | e C_ASOP e { $$ = buildtree($2, $1, $3); } + | e '?' e ':' e { + $$=buildtree(QUEST, $1, buildtree(COLON, $3, $5)); + } + | e C_OROR e { $$ = buildtree($2, $1, $3); } + | e C_ANDAND e { $$ = buildtree($2, $1, $3); } + | e '|' e { $$ = buildtree(OR, $1, $3); } + | e '^' e { $$ = buildtree(ER, $1, $3); } + | e '&' e { $$ = buildtree(AND, $1, $3); } + | e C_EQUOP e { $$ = buildtree($2, $1, $3); } + | e C_RELOP e { $$ = buildtree($2, $1, $3); } + | e C_SHIFTOP e { $$ = buildtree($2, $1, $3); } + | e '+' e { $$ = buildtree(PLUS, $1, $3); } + | e '-' e { $$ = buildtree(MINUS, $1, $3); } + | e C_DIVOP e { $$ = buildtree($2, $1, $3); } + | e '*' e { $$ = buildtree(MUL, $1, $3); } + | e '=' addrlbl { $$ = buildtree(ASSIGN, $1, $3); } + | term + ; + +addrlbl: C_ANDAND C_NAME { +#ifdef GCC_COMPAT + struct symtab *s = lookup($2, SLBLNAME); + if (s->soffset == 0) + s->soffset = -getlab(); + spname = s; + $$ = buildtree(ADDROF, buildtree(NAME, NIL, NIL), NIL); +#else + uerror("gcc extension"); +#endif + } + ; + +term: term C_INCOP { $$ = buildtree( $2, $1, bcon(1) ); } + | '*' term { $$ = buildtree(UMUL, $2, NIL); } + | '&' term { + if( ISFTN($2->n_type) || ISARY($2->n_type) ){ +#ifdef notdef + werror( "& before array or function: ignored" ); +#endif + $$ = $2; + } else + $$ = buildtree(ADDROF, $2, NIL); + } + | '-' term { $$ = buildtree(UMINUS, $2, NIL ); } + | '+' term { $$ = $2; } + | C_UNOP term { $$ = buildtree( $1, $2, NIL ); } + | C_INCOP term { + $$ = buildtree($1 == INCR ? PLUSEQ : MINUSEQ, + $2, bcon(1)); + } + | C_SIZEOF term { $$ = doszof($2); } + | '(' cast_type ')' term %prec C_INCOP { + $$ = buildtree(CAST, $2, $4); + nfree($$->n_left); + nfree($$); + $$ = $$->n_right; + } + | C_SIZEOF '(' cast_type ')' %prec C_SIZEOF { + $$ = doszof($3); + } + | '(' cast_type ')' clbrace init_list '}' { + endinit(); + spname = $4; + $$ = buildtree(NAME, NIL, NIL); + } + | term '[' e ']' { + $$ = buildtree( UMUL, + buildtree( PLUS, $1, $3 ), NIL ); + } + | funct_idn ')' { $$ = doacall($1, NIL); } + | funct_idn elist ')' { $$ = doacall($1, $2); } + | term C_STROP C_NAME { $$ = structref($1, $2, $3); } + | term C_STROP C_TYPENAME { $$ = structref($1, $2, $3); } + | C_NAME { + spname = lookup($1, 0); + /* recognize identifiers in initializations */ + if (blevel==0 && spname->stype == UNDEF) { + register NODE *q; + werror("undeclared initializer name %s", + spname->sname); + q = block(NAME, NIL, NIL, INT, 0, MKSUE(INT)); + q->n_sp = spname; + defid(q, EXTERN); + nfree(q); + } + if (spname->sflags & SINLINE) + inline_ref($1); + $$ = buildtree(NAME, NIL, NIL); + spname->suse = -lineno; + if (spname->sflags & SDYNARRAY) + $$ = buildtree(UMUL, $$, NIL); + } + | C_ICON { $$ = $1; } + | C_FCON { $$ = $1; } + | string { $$ = strend($1); /* get string contents */ } + | wstring { $$ = wstrend($1); } + | '(' e ')' { $$=$2; } + ; + +clbrace: '{' { $$ = clbrace($<nodep>-1); } + ; + +string: C_STRING { + int len = strlen($1) + 1; + $$ = tmpalloc(len); + strlcpy($$, $1, len); + } + | string C_STRING { + int len = strlen($1) + strlen($2) + 1; + $$ = tmpalloc(len); + strlcpy($$, $1, len); + strlcat($$, $2, len); + } + ; + +wstring: C_WSTRING { + int len = strlen($1) + 1; + $$ = tmpalloc(len); + strlcpy($$, $1, len); + } + | string C_WSTRING { + int len = strlen($1) + strlen($2) + 1; + $$ = tmpalloc(len); + strlcpy($$, $1, len); + strlcat($$, $2, len); + } + ; + +cast_type: specifier_qualifier_list { + $$ = tymerge($1, bdty(NAME, NULL)); + nfree($1); + } + | specifier_qualifier_list abstract_declarator { + $$ = tymerge($1, $2); + nfree($1); + } + ; + +funct_idn: C_NAME '(' { + struct symtab *s = lookup($1, 0); + if (s->stype == UNDEF) { + register NODE *q; + q = block(NAME, NIL, NIL, FTN|INT, 0, MKSUE(INT)); + q->n_sp = s; + defid(q, EXTERN); + nfree(q); + } + if (s->sflags & SINLINE) + inline_ref($1); + spname = s; + $$ = buildtree(NAME, NIL, NIL); + s->suse = -lineno; + } + | term '(' + ; +%% + +NODE * +mkty(TWORD t, union dimfun *d, struct suedef *sue) +{ + return block(TYPE, NIL, NIL, t, d, sue); +} + +static NODE * +bdty(int op, ...) +{ + va_list ap; + register NODE *q; + + va_start(ap, op); + q = block(op, NIL, NIL, INT, 0, MKSUE(INT)); + + switch (op) { + case UMUL: + case UCALL: + q->n_left = va_arg(ap, NODE *); + q->n_rval = 0; + break; + + case CALL: + q->n_left = va_arg(ap, NODE *); + q->n_right = va_arg(ap, NODE *); + break; + + case LB: + q->n_left = va_arg(ap, NODE *); + q->n_right = bcon(va_arg(ap, int)); + break; + + case NAME: + q->n_sp = va_arg(ap, struct symtab *); /* XXX survive tymerge */ + break; + + default: + cerror("bad bdty"); + } + va_end(ap); + + return q; +} + +static void +savebc(void) +{ + struct savbc *bc = tmpalloc(sizeof(struct savbc)); + + bc->brklab = brklab; + bc->contlab = contlab; + bc->flostat = flostat; + bc->next = savbc; + savbc = bc; + flostat = 0; +} + +static void +resetbc(int mask) +{ + flostat = savbc->flostat | (flostat&mask); + contlab = savbc->contlab; + brklab = savbc->brklab; + savbc = savbc->next; +} + +struct swdef { + struct swdef *next; /* Next in list */ + int deflbl; /* Label for "default" */ + struct swents *ents; /* Linked sorted list of case entries */ + int nents; /* # of entries in list */ + int num; /* Node value will end up in */ +} *swpole; + +/* + * add case to switch + */ +static void +addcase(NODE *p) +{ + struct swents *w, *sw = tmpalloc(sizeof(struct swents)); + + p = optim(p); /* change enum to ints */ + if (p->n_op != ICON || p->n_sp != NULL) { + uerror( "non-constant case expression"); + return; + } + if (swpole == NULL) { + uerror("case not in switch"); + return; + } + + sw->sval = p->n_lval; + plabel( sw->slab = getlab()); + w = swpole->ents; + if (swpole->ents == NULL) { + sw->next = NULL; + swpole->ents = sw; + } else if (swpole->ents->next == NULL) { + if (swpole->ents->sval == sw->sval) { + uerror("duplicate case in switch"); + } else if (swpole->ents->sval < sw->sval) { + sw->next = NULL; + swpole->ents->next = sw; + } else { + sw->next = swpole->ents; + swpole->ents = sw; + } + } else { + while (w->next->next != NULL && w->next->sval < sw->sval) { + w = w->next; + } + if (w->next->sval == sw->sval) { + uerror("duplicate case in switch"); + } else if (w->next->sval > sw->sval) { + sw->next = w->next; + w->next = sw; + } else { + sw->next = NULL; + w->next->next = sw; + } + } + swpole->nents++; + tfree(p); +} + +/* + * add default case to switch + */ +static void +adddef(void) +{ + if (swpole == NULL) + uerror("default not inside switch"); + else if (swpole->deflbl != 0) + uerror("duplicate default in switch"); + else + plabel( swpole->deflbl = getlab()); +} + +static void +swstart(int num) +{ + struct swdef *sw = tmpalloc(sizeof(struct swdef)); + + sw->deflbl = sw->nents = 0; + sw->ents = NULL; + sw->next = swpole; + sw->num = num; + swpole = sw; +} + +/* + * end a switch block + */ +static void +swend(void) +{ + struct swents *sw, **swp; + int i; + + sw = tmpalloc(sizeof(struct swents)); + swp = tmpalloc(sizeof(struct swents *) * (swpole->nents+1)); + + sw->slab = swpole->deflbl; + swp[0] = sw; + + for (i = 1; i <= swpole->nents; i++) { + swp[i] = swpole->ents; + swpole->ents = swpole->ents->next; + } + genswitch(swpole->num, swp, swpole->nents); + + swpole = swpole->next; +} + +/* + * Declare a variable or prototype. + */ +static struct symtab * +init_declarator(NODE *tn, NODE *p, int assign) +{ + int class = tn->n_lval; + NODE *typ; + + typ = tymerge(tn, p); + typ->n_sp = lookup((char *)typ->n_sp, 0); /* XXX */ + + if (fun_inline && ISFTN(typ->n_type)) + typ->n_sp->sflags |= SINLINE; + + if (ISFTN(typ->n_type) == 0) { + setloc1(DATA); + if (assign) { + defid(typ, class); + typ->n_sp->sflags |= SASG; + lcommdel(typ->n_sp); + } else { + nidcl(typ, class); + } + } else { + if (assign) + uerror("cannot initialise function"); + defid(typ, uclass(class)); + } + nfree(p); + return typ->n_sp; +} + +/* + * Declare a function. + */ +static void +fundef(NODE *tp, NODE *p) +{ + extern int prolab; + struct symtab *s; + int class = tp->n_lval, oclass; + char *c; + + setloc1(PROG); + /* Enter function args before they are clobbered in tymerge() */ + /* Typecheck against prototype will be done in defid(). */ + ftnarg(p); + + tymerge(tp, p); + s = p->n_sp = lookup((char *)p->n_sp, 0); /* XXX */ + + oclass = s->sclass; + if (class == STATIC && oclass == EXTERN) + werror("%s was first declared extern, then static", s->sname); + + if ((oclass == SNULL || oclass == USTATIC) && + class == STATIC && fun_inline) { + /* Unreferenced, store it for (eventual) later use */ + /* Ignore it if it not declared static */ + s->sflags |= SINLINE; + inline_start(s->sname); + } + if (class == EXTERN) + class = SNULL; /* same result */ + + cftnsp = s; + defid(p, class); + prolab = getlab(); + c = cftnsp->sname; +#ifdef GCC_COMPAT + c = gcc_findname(cftnsp); +#endif + send_passt(IP_PROLOG, -1, -1, c, cftnsp->stype, + cftnsp->sclass == EXTDEF, prolab); + blevel = 1; +#ifdef STABS + if (gflag) + stabs_func(s); +#endif + nfree(tp); + nfree(p); + +} + +static void +fend(void) +{ + if (blevel) + cerror("function level error"); + ftnend(); + fun_inline = 0; + cftnsp = NULL; +} + +static NODE * +structref(NODE *p, int f, char *name) +{ + NODE *r; + + if (f == DOT) + p = buildtree(ADDROF, p, NIL); + r = block(NAME, NIL, NIL, INT, 0, MKSUE(INT)); + r->n_name = name; + return buildtree(STREF, p, r); +} + +static void +olddecl(NODE *p) +{ + struct symtab *s; + + s = lookup((char *)p->n_sp, 0); + if (s->slevel != 1 || s->stype == UNDEF) + uerror("parameter '%s' not defined", s->sname); + else if (s->stype != FARG) + uerror("parameter '%s' redefined", s->sname); + s->stype = p->n_type; + s->sdf = p->n_df; + s->ssue = p->n_sue; + nfree(p); +} + +void +branch(int lbl) +{ + int r = reached++; + ecomp(block(GOTO, bcon(lbl), NIL, INT, 0, 0)); + reached = r; +} + +/* + * Create a printable string based on an encoded string. + */ +static char * +mkpstr(char *str) +{ + char *s, *os; + int v, l = strlen(str)+1; + + os = s = isinlining ? permalloc(l) : tmpalloc(l); + for (; *str; ) { + if (*str++ == '\\') + v = esccon(&str); + else + v = str[-1]; + *s++ = v; + } + *s = 0; + return os; +} + +static struct symtab * +clbrace(NODE *p) +{ + struct symtab *sp; + + if (blevel == 0 && xnf != NULL) + cerror("no level0 compound literals"); + + sp = getsymtab("cl", STEMP); + sp->stype = p->n_type; + sp->squal = p->n_qual; + sp->sdf = p->n_df; + sp->ssue = p->n_sue; + sp->sclass = blevel ? AUTO : STATIC; + if (!ISARY(sp->stype) || sp->sdf->ddim != 0) { + sp->soffset = NOOFFSET; + oalloc(sp, &autooff); + } + tfree(p); + beginit(sp); + return sp; +} diff --git a/usr.bin/pcc/ccom/gcc_compat.c b/usr.bin/pcc/ccom/gcc_compat.c new file mode 100644 index 00000000000..9761d814927 --- /dev/null +++ b/usr.bin/pcc/ccom/gcc_compat.c @@ -0,0 +1,126 @@ +/* $OpenBSD: gcc_compat.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Routines to support some of the gcc extensions to C. + */ +#ifdef GCC_COMPAT + +#include "pass1.h" +#include "cgram.h" + +#include <string.h> + +static struct kw { + char *name, *ptr; + int rv; +} kw[] = { + { "__asm", NULL, C_ASM }, + { "__signed", NULL, 0 }, + { "__inline", NULL, C_FUNSPEC }, + { "__const", NULL, 0 }, + { "__asm__", NULL, C_ASM }, + { NULL, NULL, 0 }, +}; + +void +gcc_init() +{ + struct kw *kwp; + + for (kwp = kw; kwp->name; kwp++) + kwp->ptr = addname(kwp->name); + +} + +/* + * See if a string matches a gcc keyword. + */ +int +gcc_keyword(char *str, NODE **n) +{ + struct kw *kwp; + int i; + + for (i = 0, kwp = kw; kwp->name; kwp++, i++) + if (str == kwp->ptr) + break; + if (kwp->name == NULL) + return 0; + if (kwp->rv) + return kwp->rv; + switch (i) { + case 1: /* __signed */ + *n = mkty((TWORD)SIGNED, 0, MKSUE(SIGNED)); + return C_TYPE; + case 3: /* __const */ + *n = block(QUALIFIER, NIL, NIL, CON, 0, 0); + return C_QUALIFIER; + } + cerror("gcc_keyword"); + return 0; +} + +static struct ren { + struct ren *next; + char *old, *new; +} *renp; +/* + * Save a name for later renaming of a variable. + */ +void +gcc_rename(struct symtab *sp, char *newname) +{ + struct ren *ren = permalloc(sizeof(struct ren)); + + sp->sflags |= SRENAME; + ren->old = sp->sname; + ren->new = newstring(newname, strlen(newname)+1); + ren->next = renp; + renp = ren; +} + +/* + * Get a renamed variable. + */ +char * +gcc_findname(struct symtab *sp) +{ + struct ren *w; + + if ((sp->sflags & SRENAME) == 0) + return exname(sp->sname); + + for (w = renp; w; w = w->next) { + if (w->old == sp->sname) + return exname(w->new); + } + cerror("gcc_findname %s", sp->sname); + return NULL; +} +#endif diff --git a/usr.bin/pcc/ccom/init.c b/usr.bin/pcc/ccom/init.c new file mode 100644 index 00000000000..47331d2c82a --- /dev/null +++ b/usr.bin/pcc/ccom/init.c @@ -0,0 +1,968 @@ +/* $OpenBSD: init.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ + +/* + * Copyright (c) 2004, 2007 Anders Magnusson (ragge@ludd.ltu.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pass1.h" +#include <string.h> + +/* + * Four machine-dependent routines may be called during initialization: + * + * instring(char *str) - Print out a string. + * zbits(OFFSZ, int) - sets int bits of zero at position OFFSZ. + * infld(CONSZ off, int fsz, CONSZ val) + * - sets the bitfield val starting at off and size fsz. + * inval(CONSZ off, int fsz, NODE *) + * - prints an integer constant which may have + * a label associated with it, located at off and + * size fsz. + * + * Initialization may be of different kind: + * - Initialization at compile-time, all values are constants and laid + * out in memory. Static or extern variables outside functions. + * - Initialization at run-time, written to their values as code. + * + * Currently run-time-initialized variables are only initialized by using + * move instructions. An optimization might be to detect that it is + * initialized with constants and therefore copied from readonly memory. + */ + +/* + * The base element(s) of an initialized variable is kept in a linked + * list, allocated while initialized. + * + * When a scalar is found, entries are popped of the instk until it's + * possible to find an entry for a new scalar; then onstk() is called + * to get the correct type and size of that scalar. + * + * If a right brace is found, pop the stack until a matching left brace + * were found while filling the elements with zeros. This left brace is + * also marking where the current level is for designated initializations. + * + * Position entries are increased when traversing back down into the stack. + */ + +/* + * Good-to-know entries from symtab: + * soffset - # of bits from beginning of this structure. + */ + +/* + * TO FIX: + * - Alignment of structs on like i386 char members. + */ + +int idebug; + +/* + * Struct used in array initialisation. + */ +static struct instk { + struct instk *in_prev; /* linked list */ + struct symtab **in_xp; /* member in structure initializations */ + struct symtab *in_sym; /* stab index */ + union dimfun *in_df; /* dimenston of array */ + TWORD in_t; /* type for this level */ + int in_n; /* number of arrays seen so far */ + int in_fl; /* flag which says if this level is controlled by {} */ +} *pstk, pbase; + +static struct symtab *csym; + +#define ISSOU(ty) (ty == STRTY || ty == UNIONTY) + +#ifdef PCC_DEBUG +static void prtstk(struct instk *in); +#endif + +/* + * Linked lists for initializations. + */ +struct ilist { + struct ilist *next; + CONSZ off; /* bit offset of this entry */ + int fsz; /* bit size of this entry */ + NODE *n; /* node containing this data info */ +}; + +struct llist { + SLIST_ENTRY(llist) next; + CONSZ begsz; /* bit offset of this entry */ + struct ilist *il; +} *curll; +static SLIST_HEAD(, llist) lpole; +static CONSZ basesz; +static int numents; /* # of array entries allocated */ + +static struct ilist * +getil(struct ilist *next, CONSZ b, int sz, NODE *n) +{ + struct ilist *il = tmpalloc(sizeof(struct ilist)); + + il->off = b; + il->fsz = sz; + il->n = n; + il->next = next; + return il; +} + +/* + * Allocate a new struct defining a block of initializers appended to the + * end of the llist. Return that entry. + */ +static struct llist * +getll(void) +{ + struct llist *ll; + + ll = tmpalloc(sizeof(struct llist)); + ll->begsz = numents * basesz; + ll->il = NULL; + SLIST_INSERT_LAST(&lpole, ll, next); + numents++; + return ll; +} + +/* + * Return structure containing off bitnumber. + * Allocate more entries, if needed. + */ +static struct llist * +setll(OFFSZ off) +{ + struct llist *ll = NULL; + + /* Ensure that we have enough entries */ + while (off >= basesz * numents) + ll = getll(); + + if (ll != NULL && ll->begsz <= off && ll->begsz + basesz > off) + return ll; + + SLIST_FOREACH(ll, &lpole, next) + if (ll->begsz <= off && ll->begsz + basesz > off) + break; + return ll; /* ``cannot fail'' */ +} + +/* + * beginning of initialization; allocate space to store initialized data. + * remember storage class for writeout in endinit(). + * p is the newly declarated type. + */ +void +beginit(struct symtab *sp) +{ + struct instk *is = &pbase; + struct llist *ll; + +#ifdef PCC_DEBUG + if (idebug) + printf("beginit(), sclass %s\n", scnames(sp->sclass)); +#endif + + csym = sp; + + numents = 0; /* no entries in array list */ + if (ISARY(sp->stype)) + basesz = tsize(DECREF(sp->stype), sp->sdf+1, sp->ssue); + else + basesz = tsize(DECREF(sp->stype), sp->sdf, sp->ssue); + SLIST_INIT(&lpole); + curll = ll = getll(); /* at least first entry in list */ + + /* first element */ + is->in_xp = ISSOU(sp->stype) ? sp->ssue->suelem : NULL; + is->in_n = 0; + is->in_t = sp->stype; + is->in_sym = sp; + is->in_df = sp->sdf; + is->in_fl = 0; + is->in_prev = NULL; + pstk = is; +} + +/* + * Push a new entry on the initializer stack. + * The new entry will be "decremented" to the new sub-type of the previous + * entry when called. + * Popping of entries is done elsewhere. + */ +static void +stkpush(void) +{ + struct instk *is; + struct symtab *sq, *sp; + TWORD t; + + if (pstk == NULL) { + sp = csym; + t = 0; + } else { + t = pstk->in_t; + sp = pstk->in_sym; + } + +#ifdef PCC_DEBUG + if (idebug) { + printf("stkpush: '%s' %s ", sp->sname, scnames(sp->sclass)); + tprint(stdout, t, 0); + printf("\n"); + } +#endif + + /* + * Figure out what the next initializer will be, and push it on + * the stack. If this is an array, just decrement type, if it + * is a struct or union, extract the next element. + */ + is = tmpalloc(sizeof(struct instk)); + is->in_fl = 0; + is->in_n = 0; + if (pstk == NULL) { + /* stack empty */ + is->in_xp = ISSOU(sp->stype) ? sp->ssue->suelem : NULL; + is->in_t = sp->stype; + is->in_sym = sp; + is->in_df = sp->sdf; + } else if (ISSOU(t)) { + sq = *pstk->in_xp; + if (sq == NULL) { + uerror("excess of initializing elements"); + } else { + is->in_xp = ISSOU(sq->stype) ? sq->ssue->suelem : 0; + is->in_t = sq->stype; + is->in_sym = sq; + is->in_df = sq->sdf; + } + } else if (ISARY(t)) { + is->in_xp = ISSOU(DECREF(t)) ? pstk->in_sym->ssue->suelem : 0; + is->in_t = DECREF(t); + is->in_sym = sp; + if (pstk->in_df->ddim && pstk->in_n >= pstk->in_df->ddim) { + werror("excess of initializing elements"); + pstk->in_n--; + } + if (ISARY(is->in_t)) + is->in_df = pstk->in_df+1; + } else + uerror("too many left braces"); + is->in_prev = pstk; + pstk = is; + +#ifdef PCC_DEBUG + if (idebug) { + printf(" newtype "); + tprint(stdout, is->in_t, 0); + printf("\n"); + } +#endif +} + +/* + * pop down to either next level that can handle a new initializer or + * to the next braced level. + */ +static void +stkpop(void) +{ +#ifdef PCC_DEBUG + if (idebug) + printf("stkpop\n"); +#endif + for (; pstk; pstk = pstk->in_prev) { + if (pstk->in_t == STRTY && pstk->in_xp[0] != NULL) { + pstk->in_xp++; + if (*pstk->in_xp != NULL) + break; + } + if (ISSOU(pstk->in_t) && pstk->in_fl) + break; /* need } */ + if (ISARY(pstk->in_t)) { + pstk->in_n++; + if (pstk->in_fl) + break; + if (pstk->in_df->ddim == 0 || + pstk->in_n < pstk->in_df->ddim) + break; /* ger more elements */ + } + } +#ifdef PCC_DEBUG + if (idebug > 1) + prtstk(pstk); +#endif +} + +/* + * Count how many elements an array may consist of. + */ +static int +acalc(struct instk *is, int n) +{ + if (is == NULL || !ISARY(is->in_t)) + return 0; + return acalc(is->in_prev, n * is->in_df->ddim) + n * is->in_n; +} + +/* + * Find current bit offset of the top element on the stack from + * the beginning of the aggregate. + */ +static CONSZ +findoff(void) +{ + struct instk *is; + OFFSZ off; + +#ifdef PCC_DEBUG + if (ISARY(pstk->in_t) || ISSOU(pstk->in_t)) + cerror("findoff on bad type"); +#endif + + /* + * Offset calculations. If: + * - previous type is STRTY, soffset has in-struct offset. + * - this type is ARY, offset is ninit*stsize. + */ + for (off = 0, is = pstk; is; is = is->in_prev) { + if (is->in_prev && is->in_prev->in_t == STRTY) + off += is->in_sym->soffset; + if (ISARY(is->in_t)) { + /* suesize is the basic type, so adjust */ + TWORD t = is->in_t; + OFFSZ o; + while (ISARY(t)) + t = DECREF(t); + o = ISPTR(t) ? SZPOINT(t) : is->in_sym->ssue->suesize; + off += o * acalc(is, 1); + while (is->in_prev && ISARY(is->in_prev->in_t)) { + if (is->in_prev->in_prev && + is->in_prev->in_prev->in_t == STRTY) + off += is->in_sym->soffset; + is = is->in_prev; + } + } + } + if (idebug>1) { + printf("findoff: off %lld\n", off); + prtstk(pstk); + } + return off; +} + +/* + * Insert the node p with size fsz at position off. + * Bit fields are already dealt with, so a node of correct type + * with correct alignment and correct bit offset is given. + */ +static void +nsetval(CONSZ off, int fsz, NODE *p) +{ + struct llist *ll; + struct ilist *il; + + if (idebug>1) + printf("setval: off %lld fsz %d p %p\n", off, fsz, p); + + if (fsz == 0) + return; + + ll = setll(off); + off -= ll->begsz; + if (ll->il == NULL) { + ll->il = getil(NULL, off, fsz, p); + } else { + il = ll->il; + if (il->off > off) { + ll->il = getil(ll->il, off, fsz, p); + } else { + for (il = ll->il; il->next; il = il->next) + if (il->off <= off && il->next->off > off) + break; + if (il->off == off) { + /* replace */ + nfree(il->n); + il->n = p; + } else + il->next = getil(il->next, off, fsz, p); + } + } +} + +/* + * Align data and set correct location. + */ +static void +setscl(struct symtab *sp) +{ + setloc1((sp->squal << TSHIFT) & CON ? RDATA : DATA); + defalign(talign(sp->stype, sp->ssue)); + if (sp->sclass == EXTDEF || + (sp->sclass == STATIC && sp->slevel == 0)) { + defnam(sp); + } else { + if (sp->soffset == NOOFFSET) + cerror("setscl"); + deflab1(sp->soffset); + } +} + +/* + * take care of generating a value for the initializer p + * inoff has the current offset (last bit written) + * in the current word being generated + */ +void +scalinit(NODE *p) +{ + CONSZ woff; + NODE *q; + int fsz; + +#ifdef PCC_DEBUG + if (idebug > 2) { + printf("scalinit(%p)\n", p); + fwalk(p, eprint, 0); + prtstk(pstk); + } +#endif + + if (nerrors) + return; + + p = optim(p); + + if (csym->sclass != AUTO && p->n_op != ICON && + p->n_op != FCON && p->n_op != NAME) + cerror("scalinit not leaf"); + + /* Out of elements? */ + if (pstk == NULL) { + uerror("excess of initializing elements"); + return; + } + + /* + * Get to the simple type if needed. + */ + while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) + stkpush(); + + /* let buildtree do typechecking (and casting) */ + q = block(NAME, NIL,NIL, pstk->in_t, pstk->in_sym->sdf, + pstk->in_sym->ssue); + p = buildtree(ASSIGN, q, p); + nfree(p->n_left); + q = optim(p->n_right); + nfree(p); + + /* bitfield sizes are special */ + if (pstk->in_sym->sclass & FIELD) + fsz = -(pstk->in_sym->sclass & FLDSIZ); + else + fsz = tsize(pstk->in_t, pstk->in_sym->sdf, pstk->in_sym->ssue); + woff = findoff(); + + nsetval(woff, fsz, q); + + stkpop(); +#ifdef PCC_DEBUG + if (idebug > 2) { + printf("scalinit e(%p)\n", p); + } +#endif +} + +/* + * Generate code to insert a value into a bitfield. + */ +static void +insbf(OFFSZ off, int fsz, int val) +{ + struct symtab sym; + NODE *p, *r; + TWORD typ; + +#ifdef PCC_DEBUG + if (idebug > 1) + printf("insbf: off %lld fsz %d val %d\n", off, fsz, val); +#endif + + if (fsz == 0) + return; + + /* small opt: do char instead of bf asg */ + if ((off & (ALCHAR-1)) == 0 && fsz == SZCHAR) + typ = CHAR; + else + typ = INT; + /* Fake a struct reference */ + spname = csym; + p = buildtree(ADDROF, + buildtree(NAME, NIL, NIL), NIL); + r = block(ICON, NIL, NIL, typ, 0, MKSUE(typ)); + sym.stype = typ; + sym.squal = 0; + sym.sdf = 0; + sym.ssue = MKSUE(typ); + sym.soffset = off; + sym.sclass = typ == INT ? FIELD | fsz : MOU; + r->n_sp = &sym; + p = block(STREF, p, r, INT, 0, MKSUE(INT)); + ecode(buildtree(ASSIGN, stref(p), bcon(val))); +} + +/* + * Clear a bitfield, starting at off and size fsz. + */ +static void +clearbf(OFFSZ off, OFFSZ fsz) +{ + /* Pad up to the next even initializer */ + if ((off & (ALCHAR-1)) || (fsz < SZCHAR)) { + int ba = ((off + (SZCHAR-1)) & ~(SZCHAR-1)) - off; + if (ba > fsz) + ba = fsz; + insbf(off, ba, 0); + off += ba; + fsz -= ba; + } + while (fsz >= SZCHAR) { + insbf(off, SZCHAR, 0); + off += SZCHAR; + fsz -= SZCHAR; + } + if (fsz) + insbf(off, fsz, 0); +} + +/* + * final step of initialization. + * print out init nodes and generate copy code (if needed). + */ +void +endinit(void) +{ + struct llist *ll; + struct ilist *il; + int fsz; + OFFSZ lastoff, tbit; + +#ifdef PCC_DEBUG + if (idebug) + printf("endinit()\n"); +#endif + + if (csym->sclass != AUTO) + setscl(csym); + + /* Calculate total block size */ + if (ISARY(csym->stype) && csym->sdf->ddim == 0) { + tbit = numents*basesz; /* open-ended arrays */ + csym->sdf->ddim = numents; + if (csym->sclass == AUTO) { /* Get stack space */ + csym->soffset = NOOFFSET; + oalloc(csym, &autooff); + } + } else + tbit = tsize(csym->stype, csym->sdf, csym->ssue); + + /* Traverse all entries and print'em out */ + lastoff = 0; + SLIST_FOREACH(ll, &lpole, next) { + for (il = ll->il; il; il = il->next) { +#ifdef PCC_DEBUG + if (idebug > 1) { + printf("off %lld size %d val %lld type ", + ll->begsz+il->off, il->fsz, il->n->n_lval); + tprint(stdout, il->n->n_type, 0); + printf("\n"); + } +#endif + fsz = il->fsz; + if (csym->sclass == AUTO) { + struct symtab sym; + NODE *p, *r, *n; + + if (ll->begsz + il->off > lastoff) + clearbf(lastoff, + (ll->begsz + il->off) - lastoff); + + /* Fake a struct reference */ + spname = csym; + p = buildtree(ADDROF, + buildtree(NAME, NIL, NIL), NIL); + n = il->n; + r = block(ICON, NIL, NIL, INT, 0, MKSUE(INT)); + sym.stype = n->n_type; + sym.squal = n->n_qual; + sym.sdf = n->n_df; + sym.ssue = n->n_sue; + sym.soffset = ll->begsz + il->off; + sym.sclass = fsz < 0 ? FIELD | -fsz : 0; + r->n_sp = &sym; + p = block(STREF, p, r, INT, 0, MKSUE(INT)); + ecode(buildtree(ASSIGN, stref(p), il->n)); + if (fsz < 0) + fsz = -fsz; + + } else { + if (ll->begsz + il->off > lastoff) + zbits(lastoff, + (ll->begsz + il->off) - lastoff); + if (fsz < 0) { + fsz = -fsz; + infld(il->off, fsz, il->n->n_lval); + } else + ninval(il->off, fsz, il->n); + nfree(il->n); + } + lastoff = ll->begsz + il->off + fsz; + } + } + if (csym->sclass == AUTO) { + clearbf(lastoff, tbit-lastoff); + } else + zbits(lastoff, tbit-lastoff); +} + +/* + * process an initializer's left brace + */ +void +ilbrace() +{ + +#ifdef PCC_DEBUG + if (idebug) + printf("ilbrace()\n"); +#endif + + if (pstk == NULL) + return; + + stkpush(); + pstk->in_fl = 1; /* mark lbrace */ +#ifdef PCC_DEBUG + if (idebug > 1) + prtstk(pstk); +#endif +} + +/* + * called when a '}' is seen + */ +void +irbrace() +{ +#ifdef PCC_DEBUG + if (idebug) + printf("irbrace()\n"); + if (idebug > 2) + prtstk(pstk); +#endif + + if (pstk == NULL) + return; + + /* Got right brace, search for corresponding in the stack */ + for (; pstk->in_prev != NULL; pstk = pstk->in_prev) { + if(!pstk->in_fl) + continue; + + /* we have one now */ + + pstk->in_fl = 0; /* cancel { */ + if (ISARY(pstk->in_t)) + pstk->in_n = pstk->in_df->ddim; + else if (pstk->in_t == STRTY) { + while (pstk->in_xp[0] != NULL && pstk->in_xp[1] != NULL) + pstk->in_xp++; + } + stkpop(); + return; + } +} + +/* + * Create a new init stack based on given elements. + */ +static void +mkstack(NODE *p) +{ + +#ifdef PCC_DEBUG + if (idebug) + printf("mkstack: %p\n", p); +#endif + + if (p == NULL) + return; + mkstack(p->n_left); + + switch (p->n_op) { + case LB: /* Array index */ + if (p->n_right->n_op != ICON) + cerror("mkstack"); + if (!ISARY(pstk->in_t)) + uerror("array indexing non-array"); + pstk->in_n = p->n_right->n_lval; + nfree(p->n_right); + break; + + case NAME: + if (pstk->in_xp) { + for (; pstk->in_xp[0]; pstk->in_xp++) + if (pstk->in_xp[0]->sname == (char *)p->n_sp) + break; + if (pstk->in_xp[0] == NULL) + uerror("member missing"); + } else { + uerror("not a struct/union"); + } + break; + default: + cerror("mkstack2"); + } + nfree(p); + stkpush(); + +} + +/* + * Initialize a specific element, as per C99. + */ +void +desinit(NODE *p) +{ + int op = p->n_op; + + if (pstk == NULL) + stkpush(); /* passed end of array */ + while (pstk->in_prev && pstk->in_fl == 0) + pstk = pstk->in_prev; /* Empty stack */ + + if (ISSOU(pstk->in_t)) + pstk->in_xp = pstk->in_sym->ssue->suelem; + + mkstack(p); /* Setup for assignment */ + + /* pop one step if SOU, ilbrace will push */ + if (op == NAME) + pstk = pstk->in_prev; + +#ifdef PCC_DEBUG + if (idebug > 1) { + printf("desinit e\n"); + prtstk(pstk); + } +#endif +} + +/* + * Convert a string to an array of char/wchar for asginit. + */ +static void +strcvt(NODE *p) +{ + char *s; + int i; + + for (s = p->n_sp->sname; *s != 0; ) { + if (*s++ == '\\') { + i = esccon(&s); + } else + i = (unsigned char)s[-1]; + asginit(bcon(i)); + } + nfree(p); +} + +/* + * Do an assignment to a struct element. + */ +void +asginit(NODE *p) +{ + int g; + +#ifdef PCC_DEBUG + if (idebug) + printf("asginit %p\n", p); + if (idebug > 1 && p) + fwalk(p, eprint, 0); +#endif + + /* convert string to array of char */ + if (p && DEUNSIGN(p->n_type) == ARY+CHAR) { + /* + * ...but only if next element is ARY+CHAR, otherwise + * just fall through. + */ + + /* HACKHACKHACK */ + struct instk *is = pstk; + + if (pstk == NULL) + stkpush(); + while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) + stkpush(); + if (pstk->in_prev && + DEUNSIGN(pstk->in_prev->in_t) == ARY+CHAR) { + pstk = pstk->in_prev; + if ((g = pstk->in_fl) == 0) + pstk->in_fl = 1; /* simulate ilbrace */ + + strcvt(p); + if (g == 0) + irbrace(); + return; + } else + pstk = is; /* no array of char */ + /* END HACKHACKHACK */ + } + + if (p == NULL) { /* only end of compound stmt */ + irbrace(); + } else /* assign next element */ + scalinit(p); +} + +#ifdef PCC_DEBUG +void +prtstk(struct instk *in) +{ + int i, o = 0; + + printf("init stack:\n"); + for (; in != NULL; in = in->in_prev) { + for (i = 0; i < o; i++) + printf(" "); + printf("%p) '%s' ", in, in->in_sym->sname); + tprint(stdout, in->in_t, 0); + printf(" %s ", scnames(in->in_sym->sclass)); + if (ISARY(in->in_t) && in->in_df->ddim) + printf("arydim=%d ", in->in_df->ddim); + printf("ninit=%d ", in->in_n); + if (BTYPE(in->in_t) == STRTY || ISARY(in->in_t)) + printf("stsize=%d ", in->in_sym->ssue->suesize); + if (in->in_fl) printf("{ "); + printf("soff=%d ", in->in_sym->soffset); + if (in->in_t == STRTY) { + if (in->in_xp && in->in_xp[0]) + printf("curel %s ", in->in_xp[0]->sname); + else + printf("END struct"); + } + printf("\n"); + o++; + } +} +#endif + +/* + * Do a simple initialization. + * At block 0, just print out the value, at higher levels generate + * appropriate code. + */ +void +simpleinit(struct symtab *sp, NODE *p) +{ + /* May be an initialization of an array of char by a string */ + if ((DEUNSIGN(p->n_type) == ARY+CHAR && + DEUNSIGN(sp->stype) == ARY+CHAR) || + (DEUNSIGN(p->n_type) == ARY+WCHAR_TYPE && + DEUNSIGN(sp->stype) == ARY+WCHAR_TYPE)) { + /* Handle "aaa" as { 'a', 'a', 'a' } */ + beginit(sp); + strcvt(p); + if (csym->sdf->ddim == 0) + scalinit(bcon(0)); /* Null-term arrays */ + endinit(); + return; + } + + switch (sp->sclass) { + case STATIC: + case EXTDEF: + spname = sp; + p = optim(buildtree(ASSIGN, buildtree(NAME, NIL, NIL), p)); + setscl(sp); + if (p->n_right->n_op != ICON && p->n_right->n_op != FCON) + uerror("initializer element is not a constant"); + else + ninval(0, p->n_right->n_sue->suesize, p->n_right); + tfree(p); + break; + + case AUTO: + case REGISTER: + if (ISARY(sp->stype)) + cerror("no array init"); + spname = sp; + ecomp(buildtree(ASSIGN, buildtree(NAME, NIL, NIL), p)); + break; + + default: + uerror("illegal initialization"); + } +} diff --git a/usr.bin/pcc/ccom/inline.c b/usr.bin/pcc/ccom/inline.c new file mode 100644 index 00000000000..c9d0a829e58 --- /dev/null +++ b/usr.bin/pcc/ccom/inline.c @@ -0,0 +1,209 @@ +/* $OpenBSD: inline.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "pass1.h" + +#include <stdarg.h> + +/* + * ilink from ipole points to the next struct in the list of functions. + */ +static struct istat { + struct istat *ilink; + char *name; + int type; +#define NOTYETR 0 /* saved but not yet referenced */ +#define NOTYETW 1 /* saved and referenced but not yet written out */ +#define WRITTEN 2 /* is written out */ +#define NOTYETD 3 /* referenced but not yet saved */ + struct interpass shead; +} *ipole, *cifun; + +#define IP_REF (MAXIP+1) + +int isinlining, recovernodes; +int inlnodecnt, inlstatcnt; + +#define ialloc() permalloc(sizeof(struct istat)); inlstatcnt++ +#define nalloc() permalloc(sizeof(NODE)) + +static void +tcnt(NODE *p) +{ + inlnodecnt++; +} + +static struct istat * +findfun(char *name) +{ + struct istat *is = ipole; + while (is) { + if (is->name == name) + return is; + is = is->ilink; + } + return NULL; +} + +static void +refnode(char *str) +{ + struct interpass *ip; + + if (sdebug) + printf("refnode(%s)\n", str); + + ip = permalloc(sizeof(*ip)); + ip->type = IP_REF; + ip->ip_name = str; + inline_addarg(ip); +} + +void +inline_addarg(struct interpass *ip) +{ + DLIST_INSERT_BEFORE(&cifun->shead, ip, qelem); + if (ip->type == IP_NODE) + walkf(ip->ip_node, tcnt); /* Count as saved */ +} + +/* + * Called to setup for inlining of a new function. + */ +void +inline_start(char *name) +{ + struct istat *is; + + if (sdebug) + printf("inline_start(\"%s\")\n", name); + + if (isinlining) + cerror("already inlining function"); + + if ((is = findfun(name)) == 0) { + is = ialloc(); + is->ilink = ipole; + ipole = is; + is->name = name; + is->type = NOTYETR; + } else { + if (is->type != NOTYETD) + cerror("inline function already defined"); + is->type = NOTYETW; + } + DLIST_INIT(&is->shead, qelem); + cifun = is; + isinlining++; +} + +void +inline_end() +{ + if (sdebug) + printf("inline_end()\n"); + + isinlining = 0; +} + +/* + * Called when an inline function is found, to be sure that it will + * be written out. + * The function may not be defined when inline_ref() is called. + */ +void +inline_ref(char *name) +{ + struct istat *w = ipole; + + if (sdebug) + printf("inline_ref(\"%s\")\n", name); + if (isinlining) { + refnode(name); + } else { + while (w != NULL) { + if (w->name == name) { + if (w->type == NOTYETR) + w->type = NOTYETW; + return; /* setup for writeout */ + } + w = w->ilink; + } + /* function not yet defined, print out when found */ + w = ialloc(); + w->ilink = ipole; + ipole = w; + w->name = name; + w->type = NOTYETD; + } +} + +static void +puto(struct istat *w) +{ + struct interpass *ip, *nip; + + /* if -O, list will be saved again so foreach cannot be used */ + ip = DLIST_NEXT(&w->shead, qelem); + while (ip != (&w->shead)) { + nip = DLIST_NEXT(ip, qelem); + DLIST_REMOVE(ip, qelem); + if (ip->type == IP_REF) + inline_ref(ip->ip_name); + else + pass2_compile(ip); + ip = nip; + } + DLIST_INIT(&w->shead, qelem); +} + +/* + * printout functions that are referenced. + */ +void +inline_prtout() +{ + struct istat *w = ipole; + int gotone = 0; + + if (w == NULL) + return; + recovernodes++; + while (w != NULL) { + if (w->type == NOTYETW) { + puto(w); + w->type = WRITTEN; + gotone++; + } + w = w->ilink; + } + if (gotone) + inline_prtout(); + recovernodes--; +} diff --git a/usr.bin/pcc/ccom/main.c b/usr.bin/pcc/ccom/main.c new file mode 100644 index 00000000000..fc4de8d774b --- /dev/null +++ b/usr.bin/pcc/ccom/main.c @@ -0,0 +1,317 @@ +/* $OpenBSD: main.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ + +/* + * Copyright (c) 2002 Anders Magnusson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> + +#include "pass1.h" +#include "pass2.h" + +int sflag, nflag, oflag, kflag; +int lflag, odebug, rdebug, radebug, vdebug, s2debug, udebug, x2debug; +#if !defined(MULTIPASS) || defined(PASST) +int iTflag, oTflag; +#endif +int xdebug, mdebug, sdebug, gflag, c2debug, pdebug; +int Wstrict_prototypes, Wmissing_prototypes, Wimplicit_int, + Wimplicit_function_declaration; +int xssaflag, xtailcallflag, xtemps, xdeljumps; + +int e2debug, t2debug, f2debug, b2debug; + +struct suedef btdims[24]; +char *prgname; + +static void prtstats(void); + +static struct { + char *n; int *f; +} flagstr[] = { + { "strict-prototypes", &Wstrict_prototypes, }, + { "missing-prototypes", &Wmissing_prototypes, }, + { "implicit-int", &Wimplicit_int, }, + { "implicit-function-declaration", &Wimplicit_function_declaration, }, + { NULL, NULL, }, +}; + +static void +usage(void) +{ + (void)fprintf(stderr, "usage: %s [option] [infile] [outfile]...\n", + prgname); + exit(1); +} + +static void +segvcatch(int a) +{ + fprintf(stderr, "%sinternal compiler error: %s, line %d\n", + nerrors ? "" : "major ", ftitle, lineno); + fflush(stderr); + exit(1); +} + +/* + * "emulate" the gcc warning flags. + */ +static void +Wflags(char *str) +{ + int i, found = 0, all; + + if (strcmp(str, "implicit") == 0) { + Wimplicit_int = Wimplicit_function_declaration = 1; + return; + } + all = strcmp(str, "W") == 0; + for (i = 0; flagstr[i].n; i++) + if (all || strcmp(flagstr[i].n, str) == 0) { + *flagstr[i].f = 1; + found++; + } + if (found == 0) + usage(); +} + + +/* control multiple files */ +int +main(int argc, char *argv[]) +{ + + int ch; + + prgname = argv[0]; + + while ((ch = getopt(argc, argv, "VlwX:Z:W:sOT:gx:kv")) != -1) + switch (ch) { +#if !defined(MULTIPASS) || defined(PASS1) + case 'X': + while (*optarg) + switch (*optarg++) { + case 'd': ++ddebug; break; /* declarations */ + case 'i': ++idebug; break; /* initializations */ + case 'b': ++bdebug; break; + case 't': ++tdebug; break; + case 'e': ++edebug; break; /* pass1 exit */ + case 'x': ++xdebug; break; /* MD code */ + case 's': ++sdebug; break; + case 'n': ++nflag; break; + case 'o': ++oflag; break; + case 'p': ++pdebug; break; /* prototype */ + default: + fprintf(stderr, "unknown X flag '%c'\n", + optarg[-1]); + exit(1); + } +#endif + break; +#if !defined(MULTIPASS) || defined(PASST) + case 'T': + while (*optarg) + switch (*optarg++) { + case 'i': ++iTflag; break; + case 'o': ++oTflag; break; + case 'n': ++nflag; break; + default: + fprintf(stderr, "unknown T flag '%c'\n", + optarg[-1]); + exit(1); + } +#endif + break; +#if !defined(MULTIPASS) || defined(PASS2) + case 'Z': + while (*optarg) + switch (*optarg++) { + case 'f': /* instruction matching */ + ++f2debug; + break; + case 'e': /* print tree upon pass2 enter */ + ++e2debug; + break; + case 'o': ++odebug; break; + case 'r': /* register alloc/graph coloring */ + ++rdebug; + break; + case 'a': ++radebug; break; + case 'b': /* basic block and SSA building */ + ++b2debug; + break; + case 'c': /* code printout */ + ++c2debug; + break; + case 'm': ++mdebug; break; + case 'v': ++vdebug; break; + case 't': ++t2debug; break; + case 's': /* shape matching */ + ++s2debug; + break; + case 'u': /* Sethi-Ullman debugging */ + ++udebug; + break; + case 'x': ++x2debug; break; + case 'n': ++nflag; break; + default: + fprintf(stderr, "unknown Z flag '%c'\n", + optarg[-1]); + exit(1); + } +#endif + break; + + case 'k': /* PIC code */ + ++kflag; + break; + + case 'l': /* linenos */ + ++lflag; + break; + + case 'g': /* Debugging */ + gflag = 1; + break; + + case 's': /* Statistics */ + ++sflag; + break; + + case 'W': /* Enable different warnings */ + Wflags(optarg); + break; + + case 'x': /* Different optimizations */ + if (strcmp(optarg, "ssa") == 0) + xssaflag++; + else if (strcmp(optarg, "tailcall") == 0) + xtailcallflag++; + else if (strcmp(optarg, "temps") == 0) + xtemps++; + else if (strcmp(optarg, "deljumps") == 0) + xdeljumps++; + else + usage(); + break; + case 'v': + printf("ccom: %s\n", VERSSTR); + break; + + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 0) { + if (freopen(argv[0], "r", stdin) == NULL) { + fprintf(stderr, "open input file '%s':", + argv[0]); + perror(NULL); + exit(1); + } + if (argc != 1) + if (freopen(argv[1], "w", stdout) == NULL) { + fprintf(stderr, "open output file '%s':", + argv[1]); + perror(NULL); + exit(1); + } + } + + mkdope(); + signal(SIGSEGV, segvcatch); + fregs = FREGS; /* number of free registers */ + lineno = 1; +#ifdef GCC_COMPAT + gcc_init(); +#endif + + /* dimension table initialization */ + + btdims[VOID].suesize = 0; + btdims[BOOL].suesize = SZBOOL; + btdims[CHAR].suesize = SZCHAR; + btdims[INT].suesize = SZINT; + btdims[FLOAT].suesize = SZFLOAT; + btdims[DOUBLE].suesize = SZDOUBLE; + btdims[LDOUBLE].suesize = SZLDOUBLE; + btdims[LONG].suesize = SZLONG; + btdims[LONGLONG].suesize = SZLONGLONG; + btdims[SHORT].suesize = SZSHORT; + btdims[UCHAR].suesize = SZCHAR; + btdims[USHORT].suesize = SZSHORT; + btdims[UNSIGNED].suesize = SZINT; + btdims[ULONG].suesize = SZLONG; + btdims[ULONGLONG].suesize = SZLONGLONG; + /* starts past any of the above */ + reached = 1; + + bjobcode(); + +#ifdef STABS + if (gflag) { + stabs_file(argc ? argv[0] : ""); + stabs_init(); + } +#endif + + (void) yyparse(); + yyaccpt(); + + ejobcode( nerrors ? 1 : 0 ); + if (!nerrors) + lcommprint(); + + if (sflag) + prtstats(); + return(nerrors?1:0); + +} + +void +prtstats(void) +{ + extern int nametabs, namestrlen, tmpallocsize, permallocsize; + extern int lostmem, arglistcnt, dimfuncnt, inlnodecnt, inlstatcnt; + extern int symtabcnt, suedefcnt; + + fprintf(stderr, "Name table entries: %d pcs\n", nametabs); + fprintf(stderr, "Name string size: %d B\n", namestrlen); + fprintf(stderr, "Permanent allocated memory: %d B\n", permallocsize); + fprintf(stderr, "Temporary allocated memory: %d B\n", tmpallocsize); + fprintf(stderr, "Lost memory: %d B\n", lostmem); + fprintf(stderr, "Argument list unions: %d pcs\n", arglistcnt); + fprintf(stderr, "Dimension/function unions: %d pcs\n", dimfuncnt); + fprintf(stderr, "Struct/union/enum blocks: %d pcs\n", suedefcnt); + fprintf(stderr, "Inline node count: %d pcs\n", inlnodecnt); + fprintf(stderr, "Inline control blocks: %d pcs\n", inlstatcnt); + fprintf(stderr, "Permanent symtab entries: %d pcs\n", symtabcnt); +} diff --git a/usr.bin/pcc/ccom/optim.c b/usr.bin/pcc/ccom/optim.c new file mode 100644 index 00000000000..3acef181c7f --- /dev/null +++ b/usr.bin/pcc/ccom/optim.c @@ -0,0 +1,355 @@ +/* $OpenBSD: optim.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +# include "pass1.h" + +# define SWAP(p,q) {sp=p; p=q; q=sp;} +# define RCON(p) (p->n_right->n_op==ICON) +# define RO(p) p->n_right->n_op +# define RV(p) p->n_right->n_lval +# define LCON(p) (p->n_left->n_op==ICON) +# define LO(p) p->n_left->n_op +# define LV(p) p->n_left->n_lval + +static int nncon(NODE *); + +int oflag = 0; + +/* remove left node */ +static NODE * +zapleft(NODE *p) +{ + NODE *q; + + q = p->n_left; + nfree(p->n_right); + nfree(p); + return q; +} + +/* + * fortran function arguments + */ +static NODE * +fortarg(NODE *p) +{ + if( p->n_op == CM ){ + p->n_left = fortarg( p->n_left ); + p->n_right = fortarg( p->n_right ); + return(p); + } + + while( ISPTR(p->n_type) ){ + p = buildtree( UMUL, p, NIL ); + } + return( optim(p) ); +} + + /* mapping relationals when the sides are reversed */ +short revrel[] ={ EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT }; + +/* + * local optimizations, most of which are probably + * machine independent + */ +NODE * +optim(NODE *p) +{ + int o, ty; + NODE *sp, *q; + int i; + TWORD t; + + if( (t=BTYPE(p->n_type))==ENUMTY || t==MOETY ) econvert(p); + if( oflag ) return(p); + + ty = coptype(p->n_op); + if( ty == LTYPE ) return(p); + + if( ty == BITYPE ) p->n_right = optim(p->n_right); + p->n_left = optim(p->n_left); + + /* collect constants */ +again: o = p->n_op; + switch(o){ + + case SCONV: + case PCONV: + return( clocal(p) ); + + case FORTCALL: + p->n_right = fortarg( p->n_right ); + break; + + case ADDROF: + if (LO(p) == TEMP) + return p; + if( LO(p) != NAME ) cerror( "& error" ); + + if( !andable(p->n_left) ) return(p); + + LO(p) = ICON; + + setuleft: + /* paint over the type of the left hand side with the type of the top */ + p->n_left->n_type = p->n_type; + p->n_left->n_df = p->n_df; + p->n_left->n_sue = p->n_sue; + q = p->n_left; + nfree(p); + return q; + + case UMUL: + if( LO(p) != ICON ) break; + LO(p) = NAME; + goto setuleft; + + case RS: + if (LO(p) == RS && RCON(p->n_left) && RCON(p)) { + /* two right-shift by constants */ + RV(p) += RV(p->n_left); + p->n_left = zapleft(p->n_left); + } +#if 0 + else if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { + RV(p) -= RV(p->n_left); + if (RV(p) < 0) + o = p->n_op = LS, RV(p) = -RV(p); + p->n_left = zapleft(p->n_left); + } +#endif + if (RO(p) == ICON) { + if (RV(p) < 0) { + RV(p) = -RV(p); + p->n_op = LS; + goto again; + } +#ifdef notyet /* must check for side effects, --a >> 32; */ + if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue) && + ISUNSIGNED(p->n_type)) { /* ignore signed shifts */ + /* too many shifts */ + tfree(p->n_left); + nfree(p->n_right); + p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL; + } else +#endif + /* avoid larger shifts than type size */ + if (RV(p) >= p->n_sue->suesize) { + RV(p) = RV(p) % p->n_sue->suesize; + werror("shift larger than type"); + } + if (RV(p) == 0) + p = zapleft(p); + } + break; + + case LS: + if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { + /* two left-shift by constants */ + RV(p) += RV(p->n_left); + p->n_left = zapleft(p->n_left); + } +#if 0 + else if (LO(p) == RS && RCON(p->n_left) && RCON(p)) { + RV(p) -= RV(p->n_left); + p->n_left = zapleft(p->n_left); + } +#endif + if (RO(p) == ICON) { + if (RV(p) < 0) { + RV(p) = -RV(p); + p->n_op = RS; + goto again; + } +#ifdef notyet /* must check for side effects */ + if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue)) { + /* too many shifts */ + tfree(p->n_left); + nfree(p->n_right); + p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL; + } else +#endif + /* avoid larger shifts than type size */ + if (RV(p) >= p->n_sue->suesize) { + RV(p) = RV(p) % p->n_sue->suesize; + werror("shift larger than type"); + } + if (RV(p) == 0) + p = zapleft(p); + } + break; + + case MINUS: + if (LCON(p) && RCON(p) && p->n_left->n_sp == p->n_right->n_sp) { + /* link-time constants, but both are the same */ + /* solve it now by forgetting the symbols */ + p->n_left->n_sp = p->n_right->n_sp = NULL; + } + if( !nncon(p->n_right) ) break; + RV(p) = -RV(p); + o = p->n_op = PLUS; + + case MUL: + case PLUS: + case AND: + case OR: + case ER: + /* commutative ops; for now, just collect constants */ + /* someday, do it right */ + if( nncon(p->n_left) || ( LCON(p) && !RCON(p) ) ) + SWAP( p->n_left, p->n_right ); + /* make ops tower to the left, not the right */ + if( RO(p) == o ){ + NODE *t1, *t2, *t3; + t1 = p->n_left; + sp = p->n_right; + t2 = sp->n_left; + t3 = sp->n_right; + /* now, put together again */ + p->n_left = sp; + sp->n_left = t1; + sp->n_right = t2; + p->n_right = t3; + } + if(o == PLUS && LO(p) == MINUS && RCON(p) && RCON(p->n_left) && + conval(p->n_right, MINUS, p->n_left->n_right)){ + zapleft: + + q = p->n_left->n_left; + nfree(p->n_left->n_right); + nfree(p->n_left); + p->n_left = q; + } + if( RCON(p) && LO(p)==o && RCON(p->n_left) && + conval( p->n_right, o, p->n_left->n_right ) ){ + goto zapleft; + } + else if( LCON(p) && RCON(p) && conval( p->n_left, o, p->n_right ) ){ + zapright: + nfree(p->n_right); + q = makety(p->n_left, p->n_type, p->n_qual, + p->n_df, p->n_sue); + nfree(p); + return clocal(q); + } + + /* change muls to shifts */ + + if( o == MUL && nncon(p->n_right) && (i=ispow2(RV(p)))>=0){ + if( i == 0 ) { /* multiplication by 1 */ + goto zapright; + } + o = p->n_op = LS; + p->n_right->n_type = INT; + p->n_right->n_df = NULL; + RV(p) = i; + } + + /* change +'s of negative consts back to - */ + if( o==PLUS && nncon(p->n_right) && RV(p)<0 ){ + RV(p) = -RV(p); + o = p->n_op = MINUS; + } + + /* remove ops with RHS 0 */ + if ((o == PLUS || o == MINUS || o == OR || o == ER) && + nncon(p->n_right) && RV(p) == 0) { + goto zapright; + } + break; + + case DIV: + if( nncon( p->n_right ) && p->n_right->n_lval == 1 ) + goto zapright; + if (LCON(p) && RCON(p) && conval(p->n_left, DIV, p->n_right)) + goto zapright; + if (RCON(p) && ISUNSIGNED(p->n_type) && (i=ispow2(RV(p))) > 0) { + p->n_op = RS; + RV(p) = i; + q = p->n_right; + if(tsize(q->n_type, q->n_df, q->n_sue) > SZINT) + p->n_right = makety(q, INT, 0, 0, MKSUE(INT)); + + break; + } + break; + + case MOD: + if (RCON(p) && ISUNSIGNED(p->n_type) && ispow2(RV(p)) > 0) { + p->n_op = AND; + RV(p) = RV(p) -1; + break; + } + break; + + case EQ: + case NE: + case LT: + case LE: + case GT: + case GE: + case ULT: + case ULE: + case UGT: + case UGE: + if( !LCON(p) ) break; + + /* exchange operands */ + + sp = p->n_left; + p->n_left = p->n_right; + p->n_right = sp; + p->n_op = revrel[p->n_op - EQ ]; + break; + + } + + return(p); + } + +int +ispow2(CONSZ c) +{ + int i; + if( c <= 0 || (c&(c-1)) ) return(-1); + for( i=0; c>1; ++i) c >>= 1; + return(i); +} + +int +nncon( p ) NODE *p; { + /* is p a constant without a name */ + return( p->n_op == ICON && p->n_sp == NULL ); + } diff --git a/usr.bin/pcc/ccom/pass1.h b/usr.bin/pcc/ccom/pass1.h new file mode 100644 index 00000000000..d93f51dbee0 --- /dev/null +++ b/usr.bin/pcc/ccom/pass1.h @@ -0,0 +1,394 @@ +/* $OpenBSD: pass1.h,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <stdarg.h> + +#include "manifest.h" + +#include "protos.h" +#include "ccconfig.h" + +/* + * Storage classes + */ +#define SNULL 0 +#define AUTO 1 +#define EXTERN 2 +#define STATIC 3 +#define REGISTER 4 +#define EXTDEF 5 +/* #define LABEL 6*/ +/* #define ULABEL 7*/ +#define MOS 8 +#define PARAM 9 +#define STNAME 10 +#define MOU 11 +#define UNAME 12 +#define TYPEDEF 13 +#define FORTRAN 14 +#define ENAME 15 +#define MOE 16 +#define UFORTRAN 17 +#define USTATIC 18 +#define ILABEL 19 + + /* field size is ORed in */ +#define FIELD 0100 +#define FLDSIZ 077 +extern char *scnames(int); + +/* + * Symbol table flags + */ +#define SNORMAL 0 +#define STAGNAME 01 +#define SLBLNAME 02 +#define SMOSNAME 03 +#define SSTRING 04 +#define NSTYPES 05 +#define SMASK 07 + +#define SSET 00010 +#define SREF 00020 +#define SNOCREAT 00040 +#define STEMP 00100 +#define SDYNARRAY 00200 +#define SINLINE 00400 +#define STNODE 01000 +#ifdef GCC_COMPAT +#define SRENAME 02000 /* Node is renamed */ +#endif +#define SASG 04000 + +#ifndef FIXDEF +#define FIXDEF(p) +#endif + + /* alignment of initialized quantities */ +#ifndef AL_INIT +#define AL_INIT ALINT +#endif + +struct rstack; +struct symtab; +union arglist; + +/* + * Dimension/prototype information. + * ddim > 0 holds the dimension of an array. + * ddim < 0 is a dynamic array and refers to a tempnode. + */ +union dimfun { + int ddim; /* Dimension of an array */ + union arglist *dfun; /* Prototype index */ +}; + +/* + * Struct/union/enum definition. + * The first element (size) is used for other types as well. + */ +struct suedef { + int suesize; /* Size of the struct */ + struct symtab **suelem;/* points to the list of elements */ + int suealign; /* Alignment of this struct */ +}; + +/* + * Argument list member info when storing prototypes. + */ +union arglist { + TWORD type; + union dimfun *df; + struct suedef *sue; +}; +#define TNULL INCREF(MOETY) /* pointer to MOETY -- impossible type */ +#define TELLIPSIS INCREF(INCREF(MOETY)) + +/* + * Symbol table definition. + * + * The symtab_hdr struct is used to save label info in NAME and ICON nodes. + */ +struct symtab_hdr { + struct symtab *h_next; /* link to other symbols in the same scope */ + int h_offset; /* offset or value */ + char h_sclass; /* storage class */ + char h_slevel; /* scope level */ + short h_sflags; /* flags, see below */ +}; + +struct symtab { + struct symtab_hdr hdr; + char *sname; + TWORD stype; /* type word */ + TWORD squal; /* qualifier word */ + union dimfun *sdf; /* ptr to the dimension/prototype array */ + struct suedef *ssue; /* ptr to the definition table */ + int suse; /* line number of last use of the variable */ +}; + +#define snext hdr.h_next +#define soffset hdr.h_offset +#define sclass hdr.h_sclass +#define slevel hdr.h_slevel +#define sflags hdr.h_sflags + +#define MKSUE(type) &btdims[type] +extern struct suedef btdims[]; + +/* + * External definitions + */ +struct swents { /* switch table */ + struct swents *next; /* Next struct in linked list */ + CONSZ sval; /* case value */ + int slab; /* associated label */ +}; +void genswitch(int, struct swents **, int); + +extern int blevel; +extern int instruct, got_type; +extern int oldstyle; + +extern int lineno, nerrors; + +extern char *ftitle; +extern struct symtab *cftnsp; +extern int autooff, maxautooff, argoff, strucoff; +extern int brkflag; +extern int lastloc; + +extern OFFSZ inoff; + +extern int reached; +extern int isinlining; + +/* tunnel to buildtree for name id's */ + +extern struct symtab *spname; + +extern int sdebug, idebug, pdebug; + +/* various labels */ +extern int brklab; +extern int contlab; +extern int flostat; +extern int retlab; + +/* + * Flags used in structures/unions + */ +#define INSTRUCT 02 +#define INUNION 04 + +/* + * Flags used in the (elementary) flow analysis ... + */ +#define FBRK 02 +#define FCONT 04 +#define FDEF 010 +#define FLOOP 020 + +/* mark an offset which is undefined */ + +#define NOOFFSET (-10201) + +/* declarations of various functions */ +extern NODE + *buildtree(int, NODE *l, NODE *r), + *mkty(unsigned, union dimfun *, struct suedef *), + *rstruct(char *, int), + *dclstruct(struct rstack *), + *strend(char *), + *wstrend(char *), + *tymerge(NODE *typ, NODE *idp), + *stref(NODE *), + *offcon(OFFSZ, TWORD, union dimfun *, struct suedef *), + *bcon(int), + *bpsize(NODE *), + *convert(NODE *, int), + *pconvert(NODE *), + *oconvert(NODE *), + *ptmatch(NODE *), + *tymatch(NODE *), + *makety(NODE *, TWORD, TWORD, union dimfun *, struct suedef *), + *block(int, NODE *, NODE *r, TWORD, union dimfun *, struct suedef *), + *doszof(NODE *), + *talloc(void), + *optim(NODE *), + *clocal(NODE *), + *ccopy(NODE *), + *btsize(TWORD, union dimfun *, struct suedef *), + *tempnode(int, TWORD type, union dimfun *df, struct suedef *sue), + *doacall(NODE *f, NODE *a); +OFFSZ tsize(TWORD, union dimfun *, struct suedef *), + psize(NODE *); +NODE * typenode(NODE *new); +void spalloc(NODE *, NODE *, OFFSZ); +char *exname(char *); + +int oalloc(struct symtab *p, int *poff); +void deflabel(char *); +void deflab1(int); +void setloc1(int); +void gotolabel(char *); +unsigned int esccon(char **sptr); +void inline_start(char *name); +void inline_end(void); +void inline_addarg(struct interpass *); +void inline_ref(char *); +void inline_prtout(void); +void ftnarg(NODE *); +struct rstack *bstruct(char *, int); +void moedef(char *); +void beginit(struct symtab *); +void simpleinit(struct symtab *, NODE *); +struct symtab *lookup(char *name, int s); +struct symtab *getsymtab(char *name, int flags); +char *addstring(char *); +char *addname(char *); +char *newstring(char *, int len); +void symclear(int level); +void schedremove(struct symtab *p); +struct symtab *hide(struct symtab *p); +int talign(unsigned int, struct suedef *); +void bfcode(struct symtab **, int); +int chkftn(union arglist *, union arglist *); +void branch(int); +void cbranch(NODE *p, NODE *q); +void extdec(struct symtab *); +void commdec(struct symtab *); +void lcommdec(struct symtab *); +int falloc(struct symtab *p, int w, int new, NODE *pty); +TWORD ctype(TWORD); +void ninval(CONSZ off, int fsz, NODE *); +void infld(CONSZ off, int fsz, CONSZ); +void zbits(CONSZ off, int fsz); +void indata(CONSZ, int); +void instring(char *); +void defnam(struct symtab *); +void plabel(int lab); +void bjobcode(void); +void ejobcode(int); +void calldec(NODE *, NODE *); +int cisreg(TWORD); +char *tmpsprintf(char *fmt, ...); +char *tmpvsprintf(char *fmt, va_list ap); +void asginit(NODE *); +void desinit(NODE *); +void endinit(void); +void ilbrace(void); +void irbrace(void); +void scalinit(NODE *p); +int ftoint(NODE *, CONSZ **); +void p1print(char *fmt, ...); +char *copst(int); +int cdope(int); +void myp2tree(NODE *); +void lcommprint(void); +void lcommdel(struct symtab *); + +#ifdef GCC_COMPAT +void gcc_init(void); +int gcc_keyword(char *, NODE **); +void gcc_rename(struct symtab *sp, char *newname); +char *gcc_findname(struct symtab *sp); +#endif + +#ifdef STABS +void stabs_init(void); +void stabs_file(char *); +void stabs_line(int); +void stabs_rbrac(int); +void stabs_lbrac(int); +void stabs_func(struct symtab *); +void stabs_newsym(struct symtab *); +void stabs_chgsym(struct symtab *); +void stabs_struct(struct symtab *p, struct suedef *sue); +#endif + +#ifndef CHARCAST +/* to make character constants into character connstants */ +/* this is a macro to defend against cross-compilers, etc. */ +#define CHARCAST(x) (char)(x) +#endif + +/* + * C compiler first pass extra defines. + */ +#define QUALIFIER (MAXOP+1) +#define CLASS (MAXOP+2) +#define RB (MAXOP+3) +#define DOT (MAXOP+4) +#define ELLIPSIS (MAXOP+5) +#define TYPE (MAXOP+6) +#define LB (MAXOP+7) +#define COMOP (MAXOP+8) +#define QUEST (MAXOP+9) +#define COLON (MAXOP+10) +#define ANDAND (MAXOP+11) +#define OROR (MAXOP+12) +#define NOT (MAXOP+13) +#define CAST (MAXOP+14) +/* #define STRING (MAXOP+15) */ + +/* The following must be in the same order as their NOASG counterparts */ +#define PLUSEQ (MAXOP+16) +#define MINUSEQ (MAXOP+17) +#define DIVEQ (MAXOP+18) +#define MODEQ (MAXOP+19) +#define MULEQ (MAXOP+20) +#define ANDEQ (MAXOP+21) +#define OREQ (MAXOP+22) +#define EREQ (MAXOP+23) +#define LSEQ (MAXOP+24) +#define RSEQ (MAXOP+25) + +#define UNASG (-(PLUSEQ-PLUS))+ + +#define INCR (MAXOP+26) +#define DECR (MAXOP+27) +/* + * The following types are only used in pass1. + */ +#define SIGNED (MAXTYPES+1) +#define BOOL (MAXTYPES+2) + + +#define coptype(o) (cdope(o)&TYFLG) +#define clogop(o) (cdope(o)&LOGFLG) +#define casgop(o) (cdope(o)&ASGFLG) + diff --git a/usr.bin/pcc/ccom/pftn.c b/usr.bin/pcc/ccom/pftn.c new file mode 100644 index 00000000000..c8f4dd49e2e --- /dev/null +++ b/usr.bin/pcc/ccom/pftn.c @@ -0,0 +1,2676 @@ +/* $OpenBSD: pftn.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Many changes from the 32V sources, among them: + * - New symbol table manager (moved to another file). + * - Prototype saving/checks. + */ + +# include "pass1.h" + +#include <string.h> /* XXX - for strcmp */ + +struct symtab *spname; +struct symtab *cftnsp; +static int strunem; /* currently parsed member type */ +int arglistcnt, dimfuncnt; /* statistics */ +int symtabcnt, suedefcnt; /* statistics */ +int autooff, /* the next unused automatic offset */ + maxautooff, /* highest used automatic offset in function */ + argoff, /* the next unused argument offset */ + strucoff; /* the next structure offset position */ +int retlab = NOLAB; /* return label for subroutine */ +int brklab; +int contlab; +int flostat; +int instruct, blevel; +int reached, prolab; + +struct params; + +#define ISSTR(ty) (ty == STRTY || ty == UNIONTY || ty == ENUMTY) +#define ISSOU(ty) (ty == STRTY || ty == UNIONTY) +#define MKTY(p, t, d, s) r = talloc(); *r = *p; \ + r = argcast(r, t, d, s); *p = *r; nfree(r); + +/* + * Info stored for delaying string printouts. + */ +struct strsched { + struct strsched *next; + int locctr; + struct symtab *sym; +} *strpole; + +/* + * Linked list stack while reading in structs. + */ +struct rstack { + struct rstack *rnext; + int rinstruct; + int rclass; + int rstrucoff; + struct params *rlparam; + struct symtab *rsym; +}; + +/* + * Linked list for parameter (and struct elements) declaration. + */ +static struct params { + struct params *next, *prev; + struct symtab *sym; +} *lpole, *lparam; +static int nparams; + +/* defines used for getting things off of the initialization stack */ + +static NODE *arrstk[10]; +static int arrstkp; +static int intcompare; + +void fixtype(NODE *p, int class); +int fixclass(int class, TWORD type); +int falloc(struct symtab *p, int w, int new, NODE *pty); +static void dynalloc(struct symtab *p, int *poff); +void inforce(OFFSZ n); +void vfdalign(int n); +static void ssave(struct symtab *); +static void strprint(void); +static void alprint(union arglist *al, int in); +static void lcommadd(struct symtab *sp); + +int ddebug = 0; + +/* + * Declaration of an identifier. Handles redeclarations, hiding, + * incomplete types and forward declarations. + */ + +void +defid(NODE *q, int class) +{ + struct symtab *p; + TWORD type, qual; + TWORD stp, stq; + int scl; + union dimfun *dsym, *ddef; + int slev, temp, changed; + + if (q == NIL) + return; /* an error was detected */ + + p = q->n_sp; + +#ifdef PCC_DEBUG + if (ddebug) { + printf("defid(%s (%p), ", p->sname, p); + tprint(stdout, q->n_type, q->n_qual); + printf(", %s, (%p,%p)), level %d\n", scnames(class), + q->n_df, q->n_sue, blevel); + } +#endif + + fixtype(q, class); + + type = q->n_type; + qual = q->n_qual; + class = fixclass(class, type); + + stp = p->stype; + stq = p->squal; + slev = p->slevel; + +#ifdef PCC_DEBUG + if (ddebug) { + printf(" modified to "); + tprint(stdout, type, qual); + printf(", %s\n", scnames(class)); + printf(" previous def'n: "); + tprint(stdout, stp, stq); + printf(", %s, (%p,%p)), level %d\n", + scnames(p->sclass), p->sdf, p->ssue, slev); + } +#endif + + if (blevel == 1) { + switch (class) { + default: + if (!(class&FIELD)) + uerror("declared argument %s missing", + p->sname ); + case MOS: + case STNAME: + case MOU: + case UNAME: + case MOE: + case ENAME: + case TYPEDEF: + ; + } + } + + if (stp == UNDEF) + goto enter; /* New symbol */ + + if (type != stp) + goto mismatch; + + if (blevel > slev && (class == AUTO || class == REGISTER)) + /* new scope */ + goto mismatch; + + /* + * test (and possibly adjust) dimensions. + * also check that prototypes are correct. + */ + dsym = p->sdf; + ddef = q->n_df; + changed = 0; + for (temp = type; temp & TMASK; temp = DECREF(temp)) { + if (ISARY(temp)) { + if (dsym->ddim == 0) { + dsym->ddim = ddef->ddim; + changed = 1; + } else if (ddef->ddim != 0 && dsym->ddim!=ddef->ddim) { + goto mismatch; + } + ++dsym; + ++ddef; + } else if (ISFTN(temp)) { + /* add a late-defined prototype here */ + if (cftnsp == NULL && dsym->dfun == NULL) + dsym->dfun = ddef->dfun; + if (!oldstyle && ddef->dfun != NULL && + chkftn(dsym->dfun, ddef->dfun)) + uerror("declaration doesn't match prototype"); + dsym++, ddef++; + } + } +#ifdef STABS + if (changed && gflag) + stabs_chgsym(p); /* symbol changed */ +#endif + + /* check that redeclarations are to the same structure */ + if ((temp == STRTY || temp == UNIONTY || temp == ENUMTY) && + p->ssue != q->n_sue && + class != STNAME && class != UNAME && class != ENAME) { + goto mismatch; + } + + scl = p->sclass; + +#ifdef PCC_DEBUG + if (ddebug) + printf(" previous class: %s\n", scnames(scl)); +#endif + + if (class&FIELD) { + /* redefinition */ + if (!falloc(p, class&FLDSIZ, 1, NIL)) { + /* successful allocation */ + ssave(p); + return; + } + /* blew it: resume at end of switch... */ + } else switch(class) { + + case EXTERN: + switch( scl ){ + case STATIC: + case USTATIC: + if( slev==0 ) return; + break; + case EXTDEF: + case EXTERN: + case FORTRAN: + case UFORTRAN: + return; + } + break; + + case STATIC: + if (scl==USTATIC || (scl==EXTERN && blevel==0)) { + p->sclass = STATIC; + return; + } + if (changed || (scl == STATIC && blevel == slev)) + return; /* identical redeclaration */ + break; + + case USTATIC: + if (scl==STATIC || scl==USTATIC) + return; + break; + + case TYPEDEF: + if (scl == class) + return; + break; + + case UFORTRAN: + if (scl == UFORTRAN || scl == FORTRAN) + return; + break; + + case FORTRAN: + if (scl == UFORTRAN) { + p->sclass = FORTRAN; + return; + } + break; + + case MOU: + case MOS: + if (scl == class) { + if (oalloc(p, &strucoff)) + break; + if (class == MOU) + strucoff = 0; + ssave(p); + return; + } + break; + + case MOE: + break; + + case EXTDEF: + switch (scl) { + case EXTERN: + p->sclass = EXTDEF; + return; + case USTATIC: + p->sclass = STATIC; + return; + } + break; + + case STNAME: + case UNAME: + case ENAME: + if (scl != class) + break; + if (p->ssue->suesize == 0) + return; /* previous entry just a mention */ + break; + + case AUTO: + case REGISTER: + ; /* mismatch.. */ + } + + mismatch: + + /* + * Only allowed for automatic variables. + */ + if (blevel == slev || class == EXTERN || class == FORTRAN || + class == UFORTRAN) { + if (ISSTR(class) && !ISSTR(p->sclass)) { + uerror("redeclaration of %s", p->sname); + return; + } + } + if (blevel == 0) + uerror("redeclaration of %s", p->sname); + q->n_sp = p = hide(p); + + enter: /* make a new entry */ + +#ifdef PCC_DEBUG + if(ddebug) + printf(" new entry made\n"); +#endif + p->stype = type; + p->squal = qual; + p->sclass = class; + p->slevel = blevel; + p->soffset = NOOFFSET; + p->suse = lineno; + if (class == STNAME || class == UNAME || class == ENAME) { + p->ssue = permalloc(sizeof(struct suedef)); + suedefcnt++; + p->ssue->suesize = 0; + p->ssue->suelem = NULL; + p->ssue->suealign = ALSTRUCT; + } else { + switch (BTYPE(type)) { + case STRTY: + case UNIONTY: + case ENUMTY: + p->ssue = q->n_sue; + break; + default: + p->ssue = MKSUE(BTYPE(type)); + } + } + + /* copy dimensions */ + p->sdf = q->n_df; + /* Do not save param info for old-style functions */ + if (ISFTN(type) && oldstyle) + p->sdf->dfun = NULL; + + /* allocate offsets */ + if (class&FIELD) { + (void) falloc(p, class&FLDSIZ, 0, NIL); /* new entry */ + ssave(p); + } else switch (class) { + + case REGISTER: + cerror("register var"); + + case AUTO: + if (arrstkp) + dynalloc(p, &autooff); + else + oalloc(p, &autooff); + break; + case STATIC: + case EXTDEF: + p->soffset = getlab(); +#ifdef GCC_COMPAT + { extern char *renname; + if (renname) + gcc_rename(p, renname); + renname = NULL; + } +#endif + break; + + case EXTERN: + case UFORTRAN: + case FORTRAN: + p->soffset = getlab(); +#ifdef notdef + /* Cannot reset level here. What does the standard say??? */ + p->slevel = 0; +#endif +#ifdef GCC_COMPAT + { extern char *renname; + if (renname) + gcc_rename(p, renname); + renname = NULL; + } +#endif + break; + case MOU: + case MOS: + oalloc(p, &strucoff); + if (class == MOU) + strucoff = 0; + ssave(p); + break; + + case MOE: + p->soffset = strucoff++; + ssave(p); + break; + + } + +#ifdef STABS + if (gflag) + stabs_newsym(p); +#endif + +#ifdef PCC_DEBUG + if (ddebug) + printf( " sdf, ssue, offset: %p, %p, %d\n", + p->sdf, p->ssue, p->soffset); +#endif + +} + +void +ssave(struct symtab *sym) +{ + struct params *p; + + p = tmpalloc(sizeof(struct params)); + p->next = NULL; + p->sym = sym; + + if (lparam == NULL) { + p->prev = (struct params *)&lpole; + lpole = p; + } else { + lparam->next = p; + p->prev = lparam; + } + lparam = p; +} + +/* + * end of function + */ +void +ftnend() +{ + extern struct savbc *savbc; + extern struct swdef *swpole; + char *c; + + if (retlab != NOLAB && nerrors == 0) { /* inside a real function */ + plabel(retlab); + efcode(); /* struct return handled here */ + c = cftnsp->sname; +#ifdef GCC_COMPAT + c = gcc_findname(cftnsp); +#endif + SETOFF(maxautooff, ALCHAR); + send_passt(IP_EPILOG, 0, maxautooff/SZCHAR, c, + cftnsp->stype, cftnsp->sclass == EXTDEF, retlab); + } + + tcheck(); + brklab = contlab = retlab = NOLAB; + flostat = 0; + if (nerrors == 0) { + if (savbc != NULL) + cerror("bcsave error"); + if (lparam != NULL) + cerror("parameter reset error"); + if (swpole != NULL) + cerror("switch error"); + } + savbc = NULL; + lparam = NULL; + maxautooff = autooff = AUTOINIT; + reached = 1; + + if (isinlining) + inline_end(); + inline_prtout(); + + strprint(); + + tmpfree(); /* Release memory resources */ +} + +void +dclargs() +{ + union dimfun *df; + union arglist *al, *al2, *alb; + struct params *a; + struct symtab *p, **parr = NULL; /* XXX gcc */ + char *c; + int i; + + argoff = ARGINIT; + + /* + * Deal with fun(void) properly. + */ + if (nparams == 1 && lparam->sym->stype == VOID) + goto done; + + /* + * Generate a list for bfcode(). + * Parameters were pushed in reverse order. + */ + if (nparams != 0) + parr = tmpalloc(sizeof(struct symtab *) * nparams); + + if (nparams) + for (a = lparam, i = 0; a != NULL && a != (struct params *)&lpole; + a = a->prev) { + + p = a->sym; + parr[i++] = p; + if (p->stype == FARG) { + p->stype = INT; + p->ssue = MKSUE(INT); + } + if (ISARY(p->stype)) { + p->stype += (PTR-ARY); + p->sdf++; + } else if (ISFTN(p->stype)) { + werror("function declared as argument"); + p->stype = INCREF(p->stype); + } + /* always set aside space, even for register arguments */ + oalloc(p, &argoff); +#ifdef STABS + if (gflag) + stabs_newsym(p); +#endif + } + if (oldstyle && (df = cftnsp->sdf) && (al = df->dfun)) { + /* + * Check against prototype of oldstyle function. + */ + alb = al2 = tmpalloc(sizeof(union arglist) * nparams * 3 + 1); + for (i = 0; i < nparams; i++) { + TWORD type = parr[i]->stype; + (al2++)->type = type; + if (ISSTR(BTYPE(type))) + (al2++)->sue = parr[i]->ssue; + while (!ISFTN(type) && !ISARY(type) && type > BTMASK) + type = DECREF(type); + if (type > BTMASK) + (al2++)->df = parr[i]->sdf; + } + al2->type = TNULL; + intcompare = 1; + if (chkftn(al, alb)) + uerror("function doesn't match prototype"); + intcompare = 0; + } +done: cendarg(); + c = cftnsp->sname; +#ifdef GCC_COMPAT + c = gcc_findname(cftnsp); +#endif +#if 0 + prolab = getlab(); + send_passt(IP_PROLOG, -1, -1, c, cftnsp->stype, + cftnsp->sclass == EXTDEF, prolab); +#endif + plabel(prolab); /* after prolog, used in optimization */ + retlab = getlab(); + bfcode(parr, nparams); + if (xtemps) { + /* put arguments in temporaries */ + for (i = 0; i < nparams; i++) { + NODE *q, *r, *s; + + p = parr[i]; + if (p->stype == STRTY || p->stype == UNIONTY || + cisreg(p->stype) == 0) + continue; + spname = p; + q = buildtree(NAME, 0, 0); + r = tempnode(0, p->stype, p->sdf, p->ssue); + s = buildtree(ASSIGN, r, q); + p->soffset = r->n_lval; + p->sflags |= STNODE; + ecomp(s); + } + plabel(getlab()); /* used when spilling */ + } + lparam = NULL; + nparams = 0; +} + +/* + * reference to a structure or union, with no definition + */ +NODE * +rstruct(char *tag, int soru) +{ + struct symtab *p; + NODE *q; + + p = (struct symtab *)lookup(tag, STAGNAME); + switch (p->stype) { + + case UNDEF: + def: + q = block(NAME, NIL, NIL, 0, 0, 0); + q->n_sp = p; + q->n_type = (soru&INSTRUCT) ? STRTY : + ((soru&INUNION) ? UNIONTY : ENUMTY); + defid(q, (soru&INSTRUCT) ? STNAME : + ((soru&INUNION) ? UNAME : ENAME)); + nfree(q); + break; + + case STRTY: + if (soru & INSTRUCT) + break; + goto def; + + case UNIONTY: + if (soru & INUNION) + break; + goto def; + + case ENUMTY: + if (!(soru&(INUNION|INSTRUCT))) + break; + goto def; + + } + q = mkty(p->stype, 0, p->ssue); + q->n_sue = p->ssue; + return q; +} + +void +moedef(char *name) +{ + NODE *q; + + q = block(NAME, NIL, NIL, MOETY, 0, 0); + q->n_sp = lookup(name, 0); + defid(q, MOE); + nfree(q); +} + +/* + * begining of structure or union declaration + */ +struct rstack * +bstruct(char *name, int soru) +{ + struct rstack *r; + struct symtab *s; + NODE *q; + + if (name != NULL) + s = lookup(name, STAGNAME); + else + s = NULL; + + r = tmpalloc(sizeof(struct rstack)); + r->rinstruct = instruct; + r->rclass = strunem; + r->rstrucoff = strucoff; + + strucoff = 0; + instruct = soru; + q = block(NAME, NIL, NIL, 0, 0, 0); + q->n_sp = s; + if (instruct==INSTRUCT) { + strunem = MOS; + q->n_type = STRTY; + if (s != NULL) + defid(q, STNAME); + } else if(instruct == INUNION) { + strunem = MOU; + q->n_type = UNIONTY; + if (s != NULL) + defid(q, UNAME); + } else { /* enum */ + strunem = MOE; + q->n_type = ENUMTY; + if (s != NULL) + defid(q, ENAME); + } + r->rsym = q->n_sp; + r->rlparam = lparam; + nfree(q); + + return r; +} + +/* + * Called after a struct is declared to restore the environment. + */ +NODE * +dclstruct(struct rstack *r) +{ + NODE *n; + struct params *l, *m; + struct suedef *sue; + struct symtab *p; + int al, sa, sz; + TWORD temp; + int i, high, low; + + if (r->rsym == NULL) { + sue = permalloc(sizeof(struct suedef)); + suedefcnt++; + sue->suesize = 0; + sue->suealign = ALSTRUCT; + } else + sue = r->rsym->ssue; + +#ifdef PCC_DEBUG + if (ddebug) + printf("dclstruct(%s)\n", r->rsym ? r->rsym->sname : "??"); +#endif + temp = (instruct&INSTRUCT)?STRTY:((instruct&INUNION)?UNIONTY:ENUMTY); + instruct = r->rinstruct; + strunem = r->rclass; + al = ALSTRUCT; + + high = low = 0; + + if ((l = r->rlparam) == NULL) + l = lpole; + else + l = l->next; + + /* memory for the element array must be allocated first */ + for (m = l, i = 1; m != NULL; m = m->next) + i++; + sue->suelem = permalloc(sizeof(struct symtab *) * i); + + for (i = 0; l != NULL; l = l->next) { + sue->suelem[i++] = p = l->sym; + + if (p == NULL) + cerror("gummy structure member"); + if (temp == ENUMTY) { + if (p->soffset < low) + low = p->soffset; + if (p->soffset > high) + high = p->soffset; + p->ssue = sue; + continue; + } + sa = talign(p->stype, p->ssue); + if (p->sclass & FIELD) { + sz = p->sclass&FLDSIZ; + } else { + sz = tsize(p->stype, p->sdf, p->ssue); + } + if (sz > strucoff) + strucoff = sz; /* for use with unions */ + /* + * set al, the alignment, to the lcm of the alignments + * of the members. + */ + SETOFF(al, sa); + } + sue->suelem[i] = NULL; + SETOFF(strucoff, al); + + if (temp == ENUMTY) { + TWORD ty; + +#ifdef ENUMSIZE + ty = ENUMSIZE(high,low); +#else + if ((char)high == high && (char)low == low) + ty = ctype(CHAR); + else if ((short)high == high && (short)low == low) + ty = ctype(SHORT); + else + ty = ctype(INT); +#endif + strucoff = tsize(ty, 0, MKSUE(ty)); + sue->suealign = al = talign(ty, MKSUE(ty)); + } + + sue->suesize = strucoff; + sue->suealign = al; + +#ifdef STABS + if (gflag) + stabs_struct(r->rsym, sue); +#endif + +#ifdef PCC_DEBUG + if (ddebug>1) { + int i; + + printf("\tsize %d align %d elem %p\n", + sue->suesize, sue->suealign, sue->suelem); + for (i = 0; sue->suelem[i] != NULL; ++i) { + printf("\tmember %s(%p)\n", + sue->suelem[i]->sname, sue->suelem[i]); + } + } +#endif + + strucoff = r->rstrucoff; + if ((lparam = r->rlparam) != NULL) + lparam->next = NULL; + n = mkty(temp, 0, sue); + return n; +} + +/* + * error printing routine in parser + */ +void yyerror(char *s); +void +yyerror(char *s) +{ + uerror(s); +} + +void yyaccpt(void); +void +yyaccpt(void) +{ + ftnend(); +} + +/* + * p is top of type list given to tymerge later. + * Find correct CALL node and declare parameters from there. + */ +void +ftnarg(NODE *p) +{ + NODE *q; + struct symtab *s; + +#ifdef PCC_DEBUG + if (ddebug > 2) + printf("ftnarg(%p)\n", p); +#endif + /* + * Enter argument onto param stack. + * Do not declare parameters until later (in dclargs); + * the function must be declared first. + * put it on the param stack in reverse order, due to the + * nature of the stack it will be reclaimed correct. + */ + for (; p->n_op != NAME; p = p->n_left) { + if (p->n_op == (UCALL) && p->n_left->n_op == NAME) + return; /* Nothing to enter */ + if (p->n_op == CALL && p->n_left->n_op == NAME) + break; + } + + p = p->n_right; + blevel = 1; + + while (p->n_op == CM) { + q = p->n_right; + if (q->n_op != ELLIPSIS) { + s = lookup((char *)q->n_sp, 0); + if (s->stype != UNDEF) { + if (s->slevel > 0) + uerror("parameter '%s' redefined", + s->sname); + s = hide(s); + } + s->soffset = NOOFFSET; + s->sclass = PARAM; + s->stype = q->n_type; + s->sdf = q->n_df; + s->ssue = q->n_sue; + ssave(s); + nparams++; +#ifdef PCC_DEBUG + if (ddebug > 2) + printf(" saving sym %s (%p) from (%p)\n", + s->sname, s, q); +#endif + } + p = p->n_left; + } + s = lookup((char *)p->n_sp, 0); + if (s->stype != UNDEF) { + if (s->slevel > 0) + uerror("parameter '%s' redefined", s->sname); + s = hide(s); + } + s->soffset = NOOFFSET; + s->sclass = PARAM; + s->stype = p->n_type; + s->sdf = p->n_df; + s->ssue = p->n_sue; + ssave(s); + if (p->n_type != VOID) + nparams++; + blevel = 0; + +#ifdef PCC_DEBUG + if (ddebug > 2) + printf(" saving sym %s (%p) from (%p)\n", + s->sname, s, p); +#endif +} + +/* + * compute the alignment of an object with type ty, sizeoff index s + */ +int +talign(unsigned int ty, struct suedef *sue) +{ + int i; + + if (ISPTR(ty)) + return(ALPOINT); /* shortcut */ + + if(sue == NULL && ty!=INT && ty!=CHAR && ty!=SHORT && + ty!=UNSIGNED && ty!=UCHAR && ty!=USHORT) { + return(fldal(ty)); + } + + for( i=0; i<=(SZINT-BTSHIFT-1); i+=TSHIFT ){ + switch( (ty>>i)&TMASK ){ + + case FTN: + cerror("compiler takes alignment of function"); + case PTR: + return(ALPOINT); + case ARY: + continue; + case 0: + break; + } + } + + switch( BTYPE(ty) ){ + + case UNIONTY: + case ENUMTY: + case STRTY: + return((unsigned int)sue->suealign); + case BOOL: + return (ALBOOL); + case CHAR: + case UCHAR: + return (ALCHAR); + case FLOAT: + return (ALFLOAT); + case LDOUBLE: + return (ALLDOUBLE); + case DOUBLE: + return (ALDOUBLE); + case LONGLONG: + case ULONGLONG: + return (ALLONGLONG); + case LONG: + case ULONG: + return (ALLONG); + case SHORT: + case USHORT: + return (ALSHORT); + default: + return (ALINT); + } +} + +/* compute the size associated with type ty, + * dimoff d, and sizoff s */ +/* BETTER NOT BE CALLED WHEN t, d, and s REFER TO A BIT FIELD... */ +OFFSZ +tsize(TWORD ty, union dimfun *d, struct suedef *sue) +{ + + int i; + OFFSZ mult, sz; + + mult = 1; + + for( i=0; i<=(SZINT-BTSHIFT-1); i+=TSHIFT ){ + switch( (ty>>i)&TMASK ){ + + case FTN: + uerror( "cannot take size of function"); + case PTR: + return( SZPOINT(ty) * mult ); + case ARY: + mult *= d->ddim; + d++; + continue; + case 0: + break; + + } + } + + if (sue == NULL) + cerror("bad tsize sue"); + sz = sue->suesize; +#ifdef GCC_COMPAT + if (ty == VOID) + sz = SZCHAR; +#endif + if (ty != STRTY && ty != UNIONTY) { + if (sz == 0) { + uerror("unknown size"); + return(SZINT); + } + } else { + if (sue->suelem == NULL) + uerror("unknown structure/union/enum"); + } + + return((unsigned int)sz * mult); +} + +/* + * Write last part of wide string. + * Do not bother to save wide strings. + */ +NODE * +wstrend(char *str) +{ + struct symtab *sp = getsymtab(str, SSTRING|STEMP); + struct strsched *sc = tmpalloc(sizeof(struct strsched)); + NODE *p = block(NAME, NIL, NIL, WCHAR_TYPE+ARY, + tmpalloc(sizeof(union dimfun)), MKSUE(WCHAR_TYPE)); + int i; + char *c; + + sp->sclass = ILABEL; + sp->soffset = getlab(); + sp->stype = WCHAR_TYPE+ARY; + + sc = tmpalloc(sizeof(struct strsched)); + sc->locctr = STRNG; + sc->sym = sp; + sc->next = strpole; + strpole = sc; + + /* length calculation, used only for sizeof */ + for (i = 0, c = str; *c; ) { + if (*c++ == '\\') + (void)esccon(&c); + i++; + } + p->n_df->ddim = (i+1) * ((MKSUE(WCHAR_TYPE))->suesize/SZCHAR); + p->n_sp = sp; + return(p); +} + +/* + * Write last part of string. + */ +NODE * +strend(char *str) +{ +// extern int maystr; + struct symtab *s; + NODE *p; + int i; + char *c; + + /* If an identical string is already emitted, just forget this one */ + str = addstring(str); /* enter string in string table */ + s = lookup(str, SSTRING); /* check for existance */ + + if (s->soffset == 0 /* && maystr == 0 */) { /* No string */ + struct strsched *sc; + s->sclass = ILABEL; + + /* + * Delay printout of this string until after the current + * function, or the end of the statement. + */ + sc = tmpalloc(sizeof(struct strsched)); + sc->locctr = STRNG; + sc->sym = s; + sc->next = strpole; + strpole = sc; + s->soffset = getlab(); + } + + p = block(NAME, NIL, NIL, CHAR+ARY, + tmpalloc(sizeof(union dimfun)), MKSUE(CHAR)); +#ifdef CHAR_UNSIGNED + p->n_type = UCHAR+ARY; +#endif + /* length calculation, used only for sizeof */ + for (i = 0, c = str; *c; ) { + if (*c++ == '\\') + (void)esccon(&c); + i++; + } + p->n_df->ddim = i+1; + p->n_sp = s; + return(p); +} + +/* + * Print out new strings, before temp memory is cleared. + */ +void +strprint() +{ + char *wr; + int i, val, isw; + NODE *p = bcon(0); + + while (strpole != NULL) { + setloc1(STRNG); + deflab1(strpole->sym->soffset); + isw = strpole->sym->stype == WCHAR_TYPE+ARY; + + i = 0; + wr = strpole->sym->sname; + while (*wr != 0) { + if (*wr++ == '\\') + val = esccon(&wr); + else + val = (unsigned char)wr[-1]; + if (isw) { + p->n_lval = val; + p->n_type = WCHAR_TYPE; + ninval(i*(WCHAR_TYPE/SZCHAR), + (MKSUE(WCHAR_TYPE))->suesize, p); + } else + bycode(val, i); + i++; + } + if (isw) { + p->n_lval = 0; + ninval(i*(WCHAR_TYPE/SZCHAR), + (MKSUE(WCHAR_TYPE))->suesize, p); + } else { + bycode(0, i++); + bycode(-1, i); + } + strpole = strpole->next; + } + nfree(p); +} + +#if 0 +/* + * simulate byte v appearing in a list of integer values + */ +void +putbyte(int v) +{ + NODE *p; + p = bcon(v); + incode( p, SZCHAR ); + tfree( p ); +// gotscal(); +} +#endif + +/* + * update the offset pointed to by poff; return the + * offset of a value of size `size', alignment `alignment', + * given that off is increasing + */ +int +upoff(int size, int alignment, int *poff) +{ + int off; + + off = *poff; + SETOFF(off, alignment); + if (off < 0) + cerror("structure or stack overgrown"); /* wrapped */ + *poff = off+size; + return (off); +} + +/* + * allocate p with offset *poff, and update *poff + */ +int +oalloc(struct symtab *p, int *poff ) +{ + int al, off, tsz; + int noff; + + /* + * Only generate tempnodes if we are optimizing, + * and only for integers, floats or pointers, + * and not if the basic type is volatile. + */ +/* XXX OLDSTYLE */ + if (xtemps && ((p->sclass == AUTO) || (p->sclass == REGISTER)) && + (p->stype < STRTY || ISPTR(p->stype)) && + !ISVOL((p->squal << TSHIFT)) && cisreg(p->stype)) { + NODE *tn = tempnode(0, p->stype, p->sdf, p->ssue); + p->soffset = tn->n_lval; + p->sflags |= STNODE; + nfree(tn); + return 0; + } + + al = talign(p->stype, p->ssue); + noff = off = *poff; + tsz = tsize(p->stype, p->sdf, p->ssue); +#ifdef BACKAUTO + if (p->sclass == AUTO) { + noff = off + tsz; + if (noff < 0) + cerror("stack overflow"); + SETOFF(noff, al); + off = -noff; + } else +#endif + if (p->sclass == PARAM && (p->stype == CHAR || p->stype == UCHAR || + p->stype == SHORT || p->stype == USHORT)) { + off = upoff(SZINT, ALINT, &noff); +#ifndef RTOLBYTES + off = noff - tsz; +#endif + } else { + off = upoff(tsz, al, &noff); + } + + if (p->sclass != REGISTER) { + /* in case we are allocating stack space for register arguments */ + if (p->soffset == NOOFFSET) + p->soffset = off; + else if(off != p->soffset) + return(1); + } + + *poff = noff; + return(0); +} + +/* + * Allocate space on the stack for dynamic arrays. + * Strategy is as follows: + * - first entry is a pointer to the dynamic datatype. + * - if it's a one-dimensional array this will be the only entry used. + * - if it's a multi-dimensional array the following (numdim-1) integers + * will contain the sizes to multiply the indexes with. + * - code to write the dimension sizes this will be generated here. + * - code to allocate space on the stack will be generated here. + */ +static void +dynalloc(struct symtab *p, int *poff) +{ + union dimfun *df; + NODE *n, *nn, *tn, *pol; + TWORD t; + int i, no; + + /* + * The pointer to the array is stored in a TEMP node, which number + * is in the soffset field; + */ + t = p->stype; + p->sflags |= (STNODE|SDYNARRAY); + p->stype = INCREF(p->stype); /* Make this an indirect pointer */ + tn = tempnode(0, p->stype, p->sdf, p->ssue); + p->soffset = tn->n_lval; + + df = p->sdf; + + pol = NIL; + for (i = 0; ISARY(t); t = DECREF(t), df++) { + if (df->ddim >= 0) + continue; + n = arrstk[i++]; + nn = tempnode(0, INT, 0, MKSUE(INT)); + no = nn->n_lval; + ecomp(buildtree(ASSIGN, nn, n)); /* Save size */ + + df->ddim = -no; + n = tempnode(no, INT, 0, MKSUE(INT)); + if (pol == NIL) + pol = n; + else + pol = buildtree(MUL, pol, n); + } + /* Create stack gap */ + if (pol == NIL) + uerror("aggregate dynamic array not allowed"); + else + spalloc(tn, pol, tsize(t, 0, p->ssue)); + arrstkp = 0; +} + +/* + * allocate a field of width w + * new is 0 if new entry, 1 if redefinition, -1 if alignment + */ +int +falloc(struct symtab *p, int w, int new, NODE *pty) +{ + int al,sz,type; + + type = (new<0)? pty->n_type : p->stype; + + /* this must be fixed to use the current type in alignments */ + switch( new<0?pty->n_type:p->stype ){ + + case ENUMTY: { + struct suedef *sue; + sue = new < 0 ? pty->n_sue : p->ssue; + al = sue->suealign; + sz = sue->suesize; + break; + } + + case CHAR: + case UCHAR: + al = ALCHAR; + sz = SZCHAR; + break; + + case SHORT: + case USHORT: + al = ALSHORT; + sz = SZSHORT; + break; + + case INT: + case UNSIGNED: + al = ALINT; + sz = SZINT; + break; + + default: + if( new < 0 ) { + uerror( "illegal field type" ); + al = ALINT; + } else + al = fldal( p->stype ); + sz =SZINT; + } + + if( w > sz ) { + uerror( "field too big"); + w = sz; + } + + if( w == 0 ){ /* align only */ + SETOFF( strucoff, al ); + if( new >= 0 ) uerror( "zero size field"); + return(0); + } + + if( strucoff%al + w > sz ) SETOFF( strucoff, al ); + if( new < 0 ) { + strucoff += w; /* we know it will fit */ + return(0); + } + + /* establish the field */ + + if( new == 1 ) { /* previous definition */ + if( p->soffset != strucoff || p->sclass != (FIELD|w) ) return(1); + } + p->soffset = strucoff; + strucoff += w; + p->stype = type; + fldty( p ); + return(0); +} + +/* + * handle unitialized declarations assumed to be not functions: + * int a; + * extern int a; + * static int a; + */ +void +nidcl(NODE *p, int class) +{ + struct symtab *sp; + int commflag = 0; + + /* compute class */ + if (class == SNULL) { + if (blevel > 1) + class = AUTO; + else if (blevel != 0 || instruct) + cerror( "nidcl error" ); + else /* blevel = 0 */ + commflag = 1, class = EXTERN; + } + + defid(p, class); + + sp = p->n_sp; + /* check if forward decl */ + if (ISARY(sp->stype) && sp->sdf->ddim == 0) + return; + + if (sp->sflags & SASG) + return; /* already initialized */ + + switch (class) { + case EXTDEF: + /* simulate initialization by 0 */ + simpleinit(p->n_sp, bcon(0)); + break; + case EXTERN: + if (commflag) + lcommadd(p->n_sp); + else + extdec(p->n_sp); + break; + case STATIC: + if (blevel == 0) + lcommadd(p->n_sp); + else + lcommdec(p->n_sp); + break; + } +} + +struct lcd { + SLIST_ENTRY(lcd) next; + struct symtab *sp; +}; + +static SLIST_HEAD(, lcd) lhead = { NULL, &lhead.q_forw}; + +/* + * Add a local common statement to the printout list. + */ +void +lcommadd(struct symtab *sp) +{ + struct lcd *lc, *lcp; + + lcp = NULL; + SLIST_FOREACH(lc, &lhead, next) { + if (lc->sp == sp) + return; /* already exists */ + if (lc->sp == NULL && lcp == NULL) + lcp = lc; + } + if (lcp == NULL) { + lc = permalloc(sizeof(struct lcd)); + lc->sp = sp; + SLIST_INSERT_LAST(&lhead, lc, next); + } else + lcp->sp = sp; +} + +/* + * Delete a local common statement. + */ +void +lcommdel(struct symtab *sp) +{ + struct lcd *lc; + + SLIST_FOREACH(lc, &lhead, next) { + if (lc->sp == sp) { + lc->sp = NULL; + return; + } + } +} + +/* + * Print out the remaining common statements. + */ +void +lcommprint(void) +{ + struct lcd *lc; + + SLIST_FOREACH(lc, &lhead, next) { + if (lc->sp != NULL) { + if (lc->sp->sclass == STATIC) + lcommdec(lc->sp); + else + commdec(lc->sp); + } + } +} + +/* + * Merges a type tree into one type. Returns one type node with merged types + * and class stored in the su field. Frees all other nodes. + * XXX - classes in typedefs? + */ +NODE * +typenode(NODE *p) +{ + NODE *l, *sp = NULL; + int class = 0, adj, noun, sign; + TWORD qual = 0; + + adj = INT; /* INT, LONG or SHORT */ + noun = UNDEF; /* INT, CHAR or FLOAT */ + sign = 0; /* 0, SIGNED or UNSIGNED */ + + /* Remove initial QUALIFIERs */ + if (p && p->n_op == QUALIFIER) { + qual = p->n_type; + l = p->n_left; + nfree(p); + p = l; + } + + /* Handle initial classes special */ + if (p && p->n_op == CLASS) { + class = p->n_type; + l = p->n_left; + nfree(p); + p = l; + } + + /* Remove more QUALIFIERs */ + if (p && p->n_op == QUALIFIER) { + qual |= p->n_type; + l = p->n_left; + nfree(p); + p = l; + } + +ag: if (p && p->n_op == TYPE) { + if (p->n_left == NIL) { +#ifdef CHAR_UNSIGNED + if (p->n_type == CHAR) + p->n_type = UCHAR; +#endif + if (p->n_type == SIGNED) + p->n_type = INT; +uni: p->n_lval = class; + p->n_qual = qual >> TSHIFT; + return p; + } else if (p->n_left->n_op == QUALIFIER) { + qual |= p->n_left->n_type; + l = p->n_left; + p->n_left = l->n_left; + nfree(l); + goto ag; + } else if (ISSTR(p->n_type)) { + /* Save node; needed for return */ + sp = p; + p = p->n_left; + } + } + + while (p != NIL) { + if (p->n_op == QUALIFIER) { + qual |= p->n_type; + goto next; + } + if (p->n_op == CLASS) { + if (class != 0) + uerror("too many storage classes"); + class = p->n_type; + goto next; + } + if (p->n_op != TYPE) + cerror("typenode got notype %d", p->n_op); + switch (p->n_type) { + case UCHAR: + case USHORT: /* may come from typedef */ + if (sign != 0 || adj != INT) + goto bad; + noun = p->n_type; + break; + case SIGNED: + case UNSIGNED: + if (sign != 0) + goto bad; + sign = p->n_type; + break; + case LONG: + if (adj == LONG) { + adj = LONGLONG; + break; + } + /* FALLTHROUGH */ + case SHORT: + if (adj != INT) + goto bad; + adj = p->n_type; + break; + case INT: + case CHAR: + case FLOAT: + case DOUBLE: + if (noun != UNDEF) + goto bad; + noun = p->n_type; + break; + case VOID: + if (noun != UNDEF || adj != INT) + goto bad; + adj = noun = VOID; + break; + case STRTY: + case UNIONTY: + break; + default: + goto bad; + } + next: + l = p->n_left; + nfree(p); + p = l; + } + + if (sp) { + p = sp; + goto uni; + } + +#ifdef CHAR_UNSIGNED + if (noun == CHAR && sign == 0) + sign = UNSIGNED; +#endif + if (noun == UNDEF) { + noun = INT; + } else if (noun == FLOAT) { + if (sign != 0 || adj == SHORT) + goto bad; + noun = (adj == LONG ? DOUBLE : FLOAT); + } else if (noun == DOUBLE) { + if (sign != 0 || adj == SHORT) + goto bad; + noun = (adj == LONG ? LDOUBLE : DOUBLE); + } else if (noun == CHAR && adj != INT) + goto bad; + + if (adj != INT && (noun != DOUBLE && noun != LDOUBLE)) + noun = adj; + if (sign == UNSIGNED) + noun += (UNSIGNED-INT); + + p = block(TYPE, NIL, NIL, noun, 0, 0); + p->n_qual = qual >> TSHIFT; + if (strunem != 0) + class = strunem; + p->n_lval = class; + return p; + +bad: uerror("illegal type combination"); + return mkty(INT, 0, 0); +} + +struct tylnk { + struct tylnk *next; + union dimfun df; +}; + +static void tyreduce(NODE *p, struct tylnk **, int *); + +static void +tylkadd(union dimfun dim, struct tylnk **tylkp, int *ntdim) +{ + (*tylkp)->next = tmpalloc(sizeof(struct tylnk)); + *tylkp = (*tylkp)->next; + (*tylkp)->next = NULL; + (*tylkp)->df = dim; + (*ntdim)++; +} + +/* merge type typ with identifier idp */ +NODE * +tymerge(NODE *typ, NODE *idp) +{ + NODE *p; + union dimfun *j; + struct tylnk *base, tylnk, *tylkp; + unsigned int t; + int ntdim, i; + + if (typ->n_op != TYPE) + cerror("tymerge: arg 1"); + +#ifdef PCC_DEBUG + if (ddebug > 2) { + printf("tymerge(%p,%p)\n", typ, idp); + fwalk(typ, eprint, 0); + fwalk(idp, eprint, 0); + } +#endif + + idp->n_type = typ->n_type; + idp->n_qual = (typ->n_qual << TSHIFT) | idp->n_qual; /* XXX ??? */ + + tylkp = &tylnk; + tylkp->next = NULL; + ntdim = 0; + + tyreduce(idp, &tylkp, &ntdim); + idp->n_sue = typ->n_sue; + + for (t = typ->n_type, j = typ->n_df; t&TMASK; t = DECREF(t)) + if (ISARY(t) || ISFTN(t)) + tylkadd(*j++, &tylkp, &ntdim); + + if (ntdim) { + union dimfun *a = permalloc(sizeof(union dimfun) * ntdim); + dimfuncnt += ntdim; + for (i = 0, base = tylnk.next; base; base = base->next, i++) + a[i] = base->df; + idp->n_df = a; + } else + idp->n_df = NULL; + + /* now idp is a single node: fix up type */ + + idp->n_type = ctype(idp->n_type); + idp->n_qual = DECQAL(idp->n_qual); + + /* in case ctype has rewritten things */ + if ((t = BTYPE(idp->n_type)) != STRTY && t != UNIONTY && t != ENUMTY) + idp->n_sue = MKSUE(t); + + if (idp->n_op != NAME) { + for (p = idp->n_left; p->n_op != NAME; p = p->n_left) + nfree(p); + nfree(p); + idp->n_op = NAME; + } + + return(idp); +} + +/* + * Retrieve all CM-separated argument types, sizes and dimensions and + * put them in an array. + * XXX - can only check first type level, side effects? + */ +static union arglist * +arglist(NODE *n) +{ + union arglist *al; + NODE *w = n, **ap; + int num, cnt, i, j, k; + TWORD ty; + +#ifdef PCC_DEBUG + if (pdebug) { + printf("arglist %p\n", n); + fwalk(n, eprint, 0); + } +#endif + /* First: how much to allocate */ + for (num = cnt = 0, w = n; w->n_op == CM; w = w->n_left) { + cnt++; /* Number of levels */ + num++; /* At least one per step */ + if (w->n_right->n_op == ELLIPSIS) + continue; + ty = w->n_right->n_type; + if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY || + BTYPE(ty) == ENUMTY) + num++; + while (ISFTN(ty) == 0 && ISARY(ty) == 0 && ty > BTMASK) + ty = DECREF(ty); + if (ty > BTMASK) + num++; + } + cnt++; + ty = w->n_type; + if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY || + BTYPE(ty) == ENUMTY) + num++; + while (ISFTN(ty) == 0 && ISARY(ty) == 0 && ty > BTMASK) + ty = DECREF(ty); + if (ty > BTMASK) + num++; + num += 2; /* TEND + last arg type */ + + /* Second: Create list to work on */ + ap = tmpalloc(sizeof(NODE *) * cnt); + al = permalloc(sizeof(union arglist) * num); + arglistcnt += num; + + for (w = n, i = 0; w->n_op == CM; w = w->n_left) + ap[i++] = w->n_right; + ap[i] = w; + + /* Third: Create actual arg list */ + for (k = 0, j = i; j >= 0; j--) { + if (ap[j]->n_op == ELLIPSIS) { + al[k++].type = TELLIPSIS; + ap[j]->n_op = ICON; /* for tfree() */ + continue; + } + /* Convert arrays to pointers */ + if (ISARY(ap[j]->n_type)) { + ap[j]->n_type += (PTR-ARY); + ap[j]->n_df++; + } + /* Convert (silently) functions to pointers */ + if (ISFTN(ap[j]->n_type)) + ap[j]->n_type = INCREF(ap[j]->n_type); + ty = ap[j]->n_type; + al[k++].type = ty; + if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY || + BTYPE(ty) == ENUMTY) + al[k++].sue = ap[j]->n_sue; + while (ISFTN(ty) == 0 && ISARY(ty) == 0 && ty > BTMASK) + ty = DECREF(ty); + if (ty > BTMASK) + al[k++].df = ap[j]->n_df; + } + al[k++].type = TNULL; + if (k > num) + cerror("arglist: k%d > num%d", k, num); + tfree(n); + if (pdebug) + alprint(al, 0); + return al; +} + +/* + * build a type, and stash away dimensions, + * from a parse tree of the declaration + * the type is build top down, the dimensions bottom up + */ +void +tyreduce(NODE *p, struct tylnk **tylkp, int *ntdim) +{ + union dimfun dim; + NODE *r = NULL; + int o; + TWORD t, q; + + o = p->n_op; + if (o == NAME) + return; + + t = INCREF(p->n_type); + q = p->n_qual; + switch (o) { + case CALL: + t += (FTN-PTR); + dim.dfun = arglist(p->n_right); + break; + case UCALL: + t += (FTN-PTR); + dim.dfun = NULL; + break; + case LB: + t += (ARY-PTR); + if (p->n_right->n_op != ICON) { + r = p->n_right; + o = RB; + } else { + dim.ddim = p->n_right->n_lval; + nfree(p->n_right); +#ifdef notdef + /* XXX - check dimensions at usage time */ + if (dim.ddim == 0 && p->n_left->n_op == LB) + uerror("null dimension"); +#endif + } + break; + } + + p->n_left->n_type = t; + p->n_left->n_qual = INCQAL(q) | p->n_left->n_qual; + tyreduce(p->n_left, tylkp, ntdim); + + if (o == LB || o == (UCALL) || o == CALL) + tylkadd(dim, tylkp, ntdim); + if (o == RB) { + dim.ddim = -1; + tylkadd(dim, tylkp, ntdim); + arrstk[arrstkp++] = r; + } + + p->n_sp = p->n_left->n_sp; + p->n_type = p->n_left->n_type; + p->n_qual = p->n_left->n_qual; +} + +static NODE * +argcast(NODE *p, TWORD t, union dimfun *d, struct suedef *sue) +{ + NODE *u, *r = talloc(); + + r->n_op = NAME; + r->n_type = t; + r->n_qual = 0; /* XXX */ + r->n_df = d; + r->n_sue = sue; + + u = buildtree(CAST, r, p); + nfree(u->n_left); + r = u->n_right; + nfree(u); + return r; +} + +#ifndef NO_C_BUILTINS +/* + * replace an alloca function with direct allocation on stack. + * return a destination temp node. + */ +static NODE * +builtin_alloca(NODE *f, NODE *a) +{ + struct symtab *sp; + NODE *t, *u; + +#ifdef notyet + if (xnobuiltins) + return NULL; +#endif + sp = f->n_sp; + + if (a == NULL || a->n_op == CM) { + uerror("wrong arg count for alloca"); + return bcon(0); + } + t = tempnode(0, VOID|PTR, 0, MKSUE(INT) /* XXX */); + u = tempnode(t->n_lval, VOID|PTR, 0, MKSUE(INT) /* XXX */); + spalloc(t, a, SZCHAR); + tfree(f); + return u; +} + +#ifndef TARGET_STDARGS +static NODE * +builtin_stdarg_start(NODE *f, NODE *a) +{ + NODE *p, *q; + int sz; + + /* check num args and type */ + if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || + !ISPTR(a->n_left->n_type)) + goto bad; + + /* must first deal with argument size; use int size */ + p = a->n_right; + if (p->n_type < INT) { + sz = SZINT/tsize(p->n_type, p->n_df, p->n_sue); + } else + sz = 1; + + /* do the real job */ + p = buildtree(ADDROF, p, NIL); /* address of last arg */ +#ifdef BACKAUTO + p = optim(buildtree(PLUS, p, bcon(sz))); /* add one to it (next arg) */ +#else + p = optim(buildtree(MINUS, p, bcon(sz))); /* add one to it (next arg) */ +#endif + q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); /* create cast node */ + q = buildtree(CAST, q, p); /* cast to void * (for assignment) */ + p = q->n_right; + nfree(q->n_left); + nfree(q); + p = buildtree(ASSIGN, a->n_left, p); /* assign to ap */ + tfree(f); + nfree(a); + return p; +bad: + uerror("bad argument to __builtin_stdarg_start"); + return bcon(0); +} + +static NODE * +builtin_va_arg(NODE *f, NODE *a) +{ + NODE *p, *q, *r; + int sz, nodnum; + + /* check num args and type */ + if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || + !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE) + goto bad; + + /* create a copy to a temp node of current ap */ + p = tcopy(a->n_left); + q = tempnode(0, p->n_type, p->n_df, p->n_sue); + nodnum = q->n_lval; + ecomp(buildtree(ASSIGN, q, p)); /* done! */ + + r = a->n_right; + sz = tsize(r->n_type, r->n_df, r->n_sue)/SZCHAR; + /* add one to ap */ +#ifdef BACKAUTO + ecomp(buildtree(PLUSEQ, a->n_left, bcon(sz))); +#else + /* XXX fix this; wrong order */ + ecomp(buildtree(MINUSEQ, a->n_left, bcon(sz))); +#endif + + nfree(a->n_right); + nfree(a); + nfree(f); + r = tempnode(nodnum, INCREF(r->n_type), r->n_df, r->n_sue); + return buildtree(UMUL, r, NIL); +bad: + uerror("bad argument to __builtin_va_arg"); + return bcon(0); + +} + +static NODE * +builtin_va_end(NODE *f, NODE *a) +{ + tfree(f); + tfree(a); + return bcon(0); /* nothing */ +} + +static NODE * +builtin_va_copy(NODE *f, NODE *a) +{ + if (a == NULL || a->n_op != CM || a->n_left->n_op == CM) + goto bad; + tfree(f); + f = buildtree(ASSIGN, a->n_left, a->n_right); + nfree(a); + return f; + +bad: + uerror("bad argument to __builtin_va_copy"); + return bcon(0); +} +#endif /* TARGET_STDARGS */ + +static struct bitable { + char *name; + NODE *(*fun)(NODE *f, NODE *a); +} bitable[] = { + { "__builtin_alloca", builtin_alloca }, + { "__builtin_stdarg_start", builtin_stdarg_start }, + { "__builtin_va_arg", builtin_va_arg }, + { "__builtin_va_end", builtin_va_end }, + { "__builtin_va_copy", builtin_va_copy }, +#ifdef TARGET_BUILTINS + TARGET_BUILTINS +#endif +}; +#endif + +#ifdef PCC_DEBUG +/* + * Print a prototype. + */ +static void +alprint(union arglist *al, int in) +{ + int i = 0, j; + + for (; al->type != TNULL; al++) { + for (j = in; j > 0; j--) + printf(" "); + printf("arg %d: ", i++); + tprint(stdout, al->type, 0); + if (BTYPE(al->type) == STRTY || + BTYPE(al->type) == UNIONTY || BTYPE(al->type) == ENUMTY) { + al++; + printf("dim %d\n", al->df->ddim); + } + printf("\n"); + if (ISFTN(DECREF(al->type))) { + al++; + alprint(al->df->dfun, in+1); + } + } + if (in == 0) + printf("end arglist\n"); +} +#endif +/* + * Do prototype checking and add conversions before calling a function. + * Argument f is function and a is a CM-separated list of arguments. + * Returns a merged node (via buildtree() of function and arguments. + */ +NODE * +doacall(NODE *f, NODE *a) +{ + NODE *w, *r; + union arglist *al; + struct ap { + struct ap *next; + NODE *node; + } *at, *apole = NULL; + int argidx/* , hasarray = 0*/; + TWORD type, arrt; + +#ifdef PCC_DEBUG + if (ddebug) { + printf("doacall.\n"); + fwalk(f, eprint, 0); + if (a) + fwalk(a, eprint, 0); + } +#endif + + /* First let MD code do something */ + calldec(f, a); +/* XXX XXX hack */ + if ((f->n_op == CALL) && + f->n_left->n_op == ADDROF && + f->n_left->n_left->n_op == NAME && + (f->n_left->n_left->n_type & 0x7e0) == 0x4c0) + goto build; +/* XXX XXX hack */ + +#ifndef NO_C_BUILTINS + /* check for builtins. function pointers are not allowed */ + if (f->n_op == NAME && + f->n_sp->sname[0] == '_' && f->n_sp->sname[1] == '_') { + int i; + + for (i = 0; i < sizeof(bitable)/sizeof(bitable[0]); i++) { + if (strcmp(bitable[i].name, f->n_sp->sname) == 0) + return (*bitable[i].fun)(f, a); + } + } +#endif + /* + * Do some basic checks. + */ + if (f->n_df == NULL || (al = f->n_df[0].dfun) == NULL) { + if (Wimplicit_function_declaration) { + if (f->n_sp != NULL) + werror("no prototype for function '%s()'", + f->n_sp->sname); + else + werror("no prototype for function pointer"); + } + /* floats must be cast to double */ + if (a == NULL) + goto build; + for (w = a; w->n_op == CM; w = w->n_left) { + if (w->n_right->n_op == TYPE) + uerror("type is not an argument"); + if (w->n_right->n_type != FLOAT) + continue; + w->n_right = argcast(w->n_right, DOUBLE, + NULL, MKSUE(DOUBLE)); + } + if (a->n_op == TYPE) + uerror("type is not an argument"); + if (a->n_type == FLOAT) { + MKTY(a, DOUBLE, 0, 0); + } + goto build; + } + if (al->type == VOID) { + if (a != NULL) + uerror("function takes no arguments"); + goto build; /* void function */ + } else { + if (a == NULL) { + uerror("function needs arguments"); + goto build; + } + } +#ifdef PCC_DEBUG + if (pdebug) { + printf("arglist for %p\n", + f->n_sp != NULL ? f->n_sp->sname : "function pointer"); + alprint(al, 0); + } +#endif + + /* + * Create a list of pointers to the nodes given as arg. + */ + for (w = a; w->n_op == CM; w = w->n_left) { + at = tmpalloc(sizeof(struct ap)); + at->node = w->n_right; + at->next = apole; + apole = at; + } + at = tmpalloc(sizeof(struct ap)); + at->node = w; + at->next = apole; + apole = at; + + /* + * Do the typechecking by walking up the list. + */ + argidx = 1; + while (al->type != TNULL) { + if (al->type == TELLIPSIS) { + /* convert the rest of float to double */ + for (; apole; apole = apole->next) { + if (apole->node->n_type != FLOAT) + continue; + MKTY(apole->node, DOUBLE, 0, 0); + } + goto build; + } + if (apole == NULL) { + uerror("too few arguments to function"); + goto build; + } +/* al = prototyp, apole = argument till ftn */ +/* type = argumentets typ, arrt = prototypens typ */ + type = apole->node->n_type; + arrt = al->type; +#if 0 + if ((hasarray = ISARY(arrt))) + arrt += (PTR-ARY); +#endif + if (ISARY(type)) + type += (PTR-ARY); + + /* Check structs */ + if (type <= BTMASK && arrt <= BTMASK) { + if (type != arrt) { + if (ISSOU(BTYPE(type)) || ISSOU(BTYPE(arrt))) { +incomp: uerror("incompatible types for arg %d", + argidx); + } else { + MKTY(apole->node, arrt, 0, 0) + } + } else if (ISSOU(BTYPE(type))) { + if (apole->node->n_sue != al[1].sue) + goto incomp; + } + goto out; + } + + /* Hereafter its only pointers (or arrays) left */ + /* Check for struct/union intermixing with other types */ + if (((type <= BTMASK) && ISSOU(BTYPE(type))) || + ((arrt <= BTMASK) && ISSOU(BTYPE(arrt)))) + goto incomp; + + /* Check for struct/union compatibility */ + if (type == arrt) { + if (ISSOU(BTYPE(type))) { + if (apole->node->n_sue == al[1].sue) + goto out; + } else + goto out; + } + if (BTYPE(arrt) == ENUMTY && BTYPE(type) == INT && + (arrt & ~BTMASK) == (type & ~BTMASK)) + goto skip; /* XXX enumty destroyed in optim() */ + if (BTYPE(arrt) == VOID && type > BTMASK) + goto skip; /* void *f = some pointer */ + if (arrt > BTMASK && BTYPE(type) == VOID) + goto skip; /* some *f = void pointer */ + if (apole->node->n_op == ICON && apole->node->n_lval == 0) + goto skip; /* Anything assigned a zero */ + + if ((type & ~BTMASK) == (arrt & ~BTMASK)) { + /* do not complain for intermixed char/uchar */ + if ((BTYPE(type) == CHAR || BTYPE(type) == UCHAR) && + (BTYPE(arrt) == CHAR || BTYPE(arrt) == UCHAR)) + goto skip; + } + + werror("implicit conversion of argument %d due to prototype", + argidx); + +skip: if (ISSTR(BTYPE(arrt))) { + MKTY(apole->node, arrt, 0, al[1].sue) + } else { + MKTY(apole->node, arrt, 0, 0) + } + +out: al++; + if (ISSTR(BTYPE(arrt))) + al++; +#if 0 + while (arrt > BTMASK && !ISFTN(arrt)) + arrt = DECREF(arrt); + if (ISFTN(arrt) || hasarray) + al++; +#else + while (arrt > BTMASK) { + if (ISARY(arrt) || ISFTN(arrt)) { + al++; + break; + } + arrt = DECREF(arrt); + } +#endif + apole = apole->next; + argidx++; + } + if (apole != NULL) + uerror("too many arguments to function"); + +build: return buildtree(a == NIL ? UCALL : CALL, f, a); +} + +static int +chk2(TWORD type, union dimfun *dsym, union dimfun *ddef) +{ + while (type > BTMASK) { + switch (type & TMASK) { + case ARY: + /* may be declared without dimension */ + if (dsym->ddim == 0) + dsym->ddim = ddef->ddim; + if (ddef->ddim && dsym->ddim != ddef->ddim) + return 1; + dsym++, ddef++; + break; + case FTN: + /* old-style function headers with function pointers + * will most likely not have a prototype. + * This is not considered an error. */ + if (ddef->dfun == NULL) { +#ifdef notyet + werror("declaration not a prototype"); +#endif + } else if (chkftn(dsym->dfun, ddef->dfun)) + return 1; + dsym++, ddef++; + break; + } + type = DECREF(type); + } + return 0; +} + +/* + * Compare two function argument lists to see if they match. + */ +int +chkftn(union arglist *usym, union arglist *udef) +{ + TWORD t2; + int ty, tyn; + + if (usym == NULL) + return 0; + if (cftnsp != NULL && udef == NULL && usym->type == VOID) + return 0; /* foo() { function with foo(void); prototype */ + if (udef == NULL && usym->type != TNULL) + return 1; + while (usym->type != TNULL) { + if (usym->type == udef->type) + goto done; + /* + * If an old-style declaration, then all types smaller than + * int are given as int parameters. + */ + if (intcompare) { + ty = BTYPE(usym->type); + tyn = BTYPE(udef->type); + if (ty == tyn || ty != INT) + return 1; + if (tyn == CHAR || tyn == UCHAR || + tyn == SHORT || tyn == USHORT) + goto done; + return 1; + } else + return 1; + +done: ty = BTYPE(usym->type); + t2 = usym->type; + if (ISSTR(ty)) { + usym++, udef++; + if (usym->sue != udef->sue) + return 1; + } + + while (ISFTN(t2) == 0 && ISARY(t2) == 0 && t2 > BTMASK) + t2 = DECREF(t2); + if (t2 > BTMASK) { + usym++, udef++; + if (chk2(t2, usym->df, udef->df)) + return 1; + } + usym++, udef++; + } + if (usym->type != udef->type) + return 1; + return 0; +} + +void +fixtype(NODE *p, int class) +{ + unsigned int t, type; + int mod1, mod2; + /* fix up the types, and check for legality */ + + if( (type = p->n_type) == UNDEF ) return; + if ((mod2 = (type&TMASK))) { + t = DECREF(type); + while( mod1=mod2, mod2 = (t&TMASK) ){ + if( mod1 == ARY && mod2 == FTN ){ + uerror( "array of functions is illegal" ); + type = 0; + } + else if( mod1 == FTN && ( mod2 == ARY || mod2 == FTN ) ){ + uerror( "function returns illegal type" ); + type = 0; + } + t = DECREF(t); + } + } + + /* detect function arguments, watching out for structure declarations */ + if (instruct && ISFTN(type)) { + uerror("function illegal in structure or union"); + type = INCREF(type); + } + p->n_type = type; +} + +/* + * give undefined version of class + */ +int +uclass(int class) +{ + if (class == SNULL) + return(EXTERN); + else if (class == STATIC) + return(USTATIC); + else if (class == FORTRAN) + return(UFORTRAN); + else + return(class); +} + +int +fixclass(int class, TWORD type) +{ + /* first, fix null class */ + if (class == SNULL) { + if (instruct&INSTRUCT) + class = MOS; + else if (instruct&INUNION) + class = MOU; + else if (blevel == 0) + class = EXTDEF; + else + class = AUTO; + } + + /* now, do general checking */ + + if( ISFTN( type ) ){ + switch( class ) { + default: + uerror( "function has illegal storage class" ); + case AUTO: + class = EXTERN; + case EXTERN: + case EXTDEF: + case FORTRAN: + case TYPEDEF: + case STATIC: + case UFORTRAN: + case USTATIC: + ; + } + } + + if( class&FIELD ){ + if( !(instruct&INSTRUCT) ) uerror( "illegal use of field" ); + return( class ); + } + + switch( class ){ + + case MOU: + if( !(instruct&INUNION) ) uerror( "illegal MOU class" ); + return( class ); + + case MOS: + if( !(instruct&INSTRUCT) ) uerror( "illegal MOS class" ); + return( class ); + + case MOE: + if( instruct & (INSTRUCT|INUNION) ) uerror( "illegal MOE class" ); + return( class ); + + case REGISTER: + if (blevel == 0) + uerror( "illegal register declaration" ); + if (blevel == 1) + return(PARAM); + else + return(AUTO); + + case AUTO: + if( blevel < 2 ) uerror( "illegal ULABEL class" ); + return( class ); + + case UFORTRAN: + case FORTRAN: +# ifdef NOFORTRAN + NOFORTRAN; /* a condition which can regulate the FORTRAN usage */ +# endif + if( !ISFTN(type) ) uerror( "fortran declaration must apply to function" ); + else { + type = DECREF(type); + if( ISFTN(type) || ISARY(type) || ISPTR(type) ) { + uerror( "fortran function has wrong type" ); + } + } + case STNAME: + case UNAME: + case ENAME: + case EXTERN: + case STATIC: + case EXTDEF: + case TYPEDEF: + case USTATIC: + return( class ); + + default: + cerror( "illegal class: %d", class ); + /* NOTREACHED */ + + } + return 0; /* XXX */ +} + +/* + * Generates a goto statement; sets up label number etc. + */ +void +gotolabel(char *name) +{ + struct symtab *s = lookup(name, SLBLNAME); + + if (s->soffset == 0) + s->soffset = -getlab(); + branch(s->soffset < 0 ? -s->soffset : s->soffset); +} + +/* + * Sets a label for gotos. + */ +void +deflabel(char *name) +{ + struct symtab *s = lookup(name, SLBLNAME); + + if (s->soffset > 0) + uerror("label '%s' redefined", name); + if (s->soffset == 0) + s->soffset = getlab(); + if (s->soffset < 0) + s->soffset = -s->soffset; + plabel( s->soffset); +} + +struct symtab * +getsymtab(char *name, int flags) +{ + struct symtab *s; + + if (flags & STEMP) { + s = tmpalloc(sizeof(struct symtab)); + } else { + s = permalloc(sizeof(struct symtab)); + symtabcnt++; + } + s->sname = name; + s->snext = NULL; + s->stype = UNDEF; + s->squal = 0; + s->sclass = SNULL; + s->sflags = flags & SMASK; + s->soffset = 0; + s->slevel = blevel; + s->sdf = NULL; + s->ssue = NULL; + s->suse = 0; + return s; +} + +#ifdef PCC_DEBUG +static char * +ccnames[] = { /* names of storage classes */ + "SNULL", + "AUTO", + "EXTERN", + "STATIC", + "REGISTER", + "EXTDEF", + "LABEL", + "ULABEL", + "MOS", + "PARAM", + "STNAME", + "MOU", + "UNAME", + "TYPEDEF", + "FORTRAN", + "ENAME", + "MOE", + "UFORTRAN", + "USTATIC", + }; + +char * +scnames(int c) +{ + /* return the name for storage class c */ + static char buf[12]; + if( c&FIELD ){ + snprintf( buf, sizeof(buf), "FIELD[%d]", c&FLDSIZ ); + return( buf ); + } + return( ccnames[c] ); + } +#endif diff --git a/usr.bin/pcc/ccom/scan.l b/usr.bin/pcc/ccom/scan.l new file mode 100644 index 00000000000..93240ae4805 --- /dev/null +++ b/usr.bin/pcc/ccom/scan.l @@ -0,0 +1,467 @@ +%{ +/* $OpenBSD: scan.l,v 1.1 2007/10/07 17:58:51 otto Exp $ */ + +/* + * Copyright (c) 2002 Anders Magnusson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +%} + + +D [0-9] +L [a-zA-Z_] +H [a-fA-F0-9] +E [Ee][+-]?{D}+ +P [Pp][+-]?{D}+ +FS (f|F|l|L) +IS (u|U|l|L)* + +%{ +#include <errno.h> +#include <string.h> +#include <stdarg.h> + +#include "pass1.h" +#include "cgram.h" + +static NODE *cvtdig(int radix); +static NODE *charcon(void); +static void control(int); +static NODE *floatcon(void); +static NODE *fhexcon(void); +int notype, parbal; + +#define CPP_PRAGMA 1 +#define CPP_IDENT 2 +#define CPP_LINE 3 +#define CPP_HASH 4 + +#ifdef STABS +#define STABS_LINE(x) if (gflag && blevel) stabs_line(x) +#else +#define STABS_LINE(x) +#endif +#if defined(FLEX_SCANNER) && YY_FLEX_SUBMINOR_VERSION >= 31 +/* Hack to avoid unneccessary warnings */ +FILE *yyget_in (void); +FILE *yyget_out (void); +int yyget_leng (void); +char *yyget_text (void); +void yyset_in (FILE * in_str ); +void yyset_out (FILE * out_str ); +int yyget_debug (void); +void yyset_debug (int bdebug ); +int yylex_destroy (void); +extern int yyget_lineno (void); +extern void yyset_lineno (int); +#endif + +%} + +%% + +"__func__" { + if (cftnsp == NULL) + uerror("__func__ outside function"); + yylval.strp = cftnsp->sname; /* XXX - not C99 */ + return(C_STRING); + } +"asm" { return(C_ASM); } +"auto" { yylval.intval = AUTO; return(C_CLASS); } +"_Bool" { yylval.nodep = mkty((TWORD)BOOL, 0, MKSUE(BOOL)); + return(C_TYPE); } +"break" { return(C_BREAK); } +"case" { return(C_CASE); } +"char" { yylval.nodep = mkty((TWORD)CHAR, 0, MKSUE(CHAR)); + notype=1; return(C_TYPE); } +"const" { yylval.nodep = + block(QUALIFIER, NIL, NIL, CON, 0, 0); + return(C_QUALIFIER); } +"continue" { return(C_CONTINUE); } +"default" { return(C_DEFAULT); } +"do" { return(C_DO); } +"double" { yylval.nodep = mkty((TWORD)DOUBLE, 0, MKSUE(DOUBLE)); + notype=1; return(C_TYPE); } +"else" { return(C_ELSE); } +"enum" { notype=1; return(C_ENUM); } +"extern" { yylval.intval = EXTERN; return(C_CLASS); } +"float" { yylval.nodep = mkty((TWORD)FLOAT, 0, MKSUE(FLOAT)); + notype=1; return(C_TYPE); } +"for" { return(C_FOR); } +"goto" { return(C_GOTO); } +"if" { return(C_IF); } +"inline" { return(C_FUNSPEC); } +"int" { yylval.nodep = mkty((TWORD)INT, 0, MKSUE(INT)); + notype=1; return(C_TYPE); } +"long" { yylval.nodep = mkty((TWORD)LONG, 0, MKSUE(LONG)); + notype=1; return(C_TYPE); } +"register" { yylval.intval = REGISTER; return(C_CLASS); } +"restrict" { ; /* just ignore */ } +"return" { return(C_RETURN); } +"short" { yylval.nodep = mkty((TWORD)SHORT, 0, MKSUE(SHORT)); + notype=1; return(C_TYPE); } +"signed" { yylval.nodep = mkty((TWORD)SIGNED, 0, MKSUE(SIGNED)); + notype=1; return(C_TYPE); } +"sizeof" { return(C_SIZEOF); } +"static" { yylval.intval = STATIC; return(C_CLASS); } +"struct" { yylval.intval = INSTRUCT; notype=1; return(C_STRUCT); } +"switch" { return(C_SWITCH); } +"typedef" { yylval.intval = TYPEDEF; return(C_CLASS); } +"union" { yylval.intval = INUNION; notype=1; return(C_STRUCT); } +"unsigned" { yylval.nodep = mkty((TWORD)UNSIGNED, 0, MKSUE(UNSIGNED)); + notype=1; return(C_TYPE); } +"void" { yylval.nodep = mkty((TWORD)VOID, 0, MKSUE(VOID)); + notype=1; return(C_TYPE); } +"volatile" { yylval.nodep = + block(QUALIFIER, NIL, NIL, VOL, 0, 0); + return(C_QUALIFIER); } +"while" { return(C_WHILE); } + +{L}({L}|{D})* { struct symtab *s; + int i; + + yylval.strp = addname(yytext); + if ((i = gcc_keyword(yylval.strp, + &yylval.nodep)) != 0) + return i; +// printf("str: %s notype %d parbal %d\n", yytext, notype, parbal); + if (!notype) { + s = lookup(yylval.strp, SNOCREAT); + if (s && s->sclass == TYPEDEF) + return notype=1, C_TYPENAME; + } + return(C_NAME); + } + +0[xX]{H}+{IS}? { yylval.nodep = cvtdig(16); return(C_ICON); } +0{D}+{IS}? { yylval.nodep = cvtdig(8); return(C_ICON); } +{D}+{IS}? { yylval.nodep = cvtdig(10); return(C_ICON); } +L?'(\\.|[^\\'])+' { yylval.nodep = charcon(); return(C_ICON); } + +{D}+{E}{FS}? { yylval.nodep = floatcon(); return(C_FCON); } +{D}*"."{D}+({E})?{FS}? { yylval.nodep = floatcon(); return(C_FCON); } +{D}+"."{D}*({E})?{FS}? { yylval.nodep = floatcon(); return(C_FCON); } +0[xX]{H}*"."{H}+{P}{FS}? { yylval.nodep = fhexcon(); return(C_FCON); } +0[xX]{H}+"."{P}{FS}? { yylval.nodep = fhexcon(); return(C_FCON); } +0[xX]{H}+{P}{FS}? { yylval.nodep = fhexcon(); return(C_FCON); } + +L?\"(\\.|[^\\"])*\" { + char *c = yytext; + int i = yyleng-2, rv; + + if (*c++ == 'L') { + c++, i--; + rv = C_WSTRING; + } else + rv = C_STRING; + c[i] = 0; /* last " */ + yylval.strp = c; + return rv; + } +"..." { return(C_ELLIPSIS); } +">>=" { yylval.intval = RSEQ; return(C_ASOP); } +"<<=" { yylval.intval = LSEQ; return(C_ASOP); } +"+=" { yylval.intval = PLUSEQ; return(C_ASOP); } +"-=" { yylval.intval = MINUSEQ; return(C_ASOP); } +"*=" { yylval.intval = MULEQ; return(C_ASOP); } +"/=" { yylval.intval = DIVEQ; return(C_ASOP); } +"%=" { yylval.intval = MODEQ; return(C_ASOP); } +"&=" { yylval.intval = ANDEQ; return(C_ASOP); } +"^=" { yylval.intval = EREQ; return(C_ASOP); } +"|=" { yylval.intval = OREQ; return(C_ASOP); } +">>" { yylval.intval = RS; return(C_SHIFTOP); } +"<<" { yylval.intval = LS; return(C_SHIFTOP); } +"++" { yylval.intval = INCR; return(C_INCOP); } +"--" { yylval.intval = DECR; return(C_INCOP); } +"->" { yylval.intval = STREF; return(C_STROP); } +"&&" { yylval.intval = ANDAND; return(C_ANDAND); } +"||" { yylval.intval = OROR; return(C_OROR); } +"<=" { yylval.intval = LE; return(C_RELOP); } +">=" { yylval.intval = GE; return(C_RELOP); } +"==" { yylval.intval = EQ; return(C_EQUOP); } +"!=" { yylval.intval = NE; return(C_EQUOP); } +";" { notype = 0; return(';'); } +("{"|"<%") { notype = 0; return('{'); } +("}"|"%>") { return('}'); } +"," { if (parbal) notype = 0; return(','); } +":" { return(':'); } +"=" { return('='); } +"(" { parbal++; notype = 0; return('('); } +")" { parbal--; if (parbal==0) { notype = 0; } return(')'); } +("["|"<:") { return('['); } +("]"|":>") { return(']'); } +"." { yylval.intval = DOT; return(C_STROP); } +"&" { return('&'); } +"!" { yylval.intval = NOT; return(C_UNOP); } +"~" { yylval.intval = COMPL; return(C_UNOP); } +"-" { return('-'); } +"+" { return('+'); } +"*" { if (parbal && notype == 0) notype = 1; return('*'); } +"/" { yylval.intval = DIV; return(C_DIVOP); } +"%" { yylval.intval = MOD; return(C_DIVOP); } +"<" { yylval.intval = LT; return(C_RELOP); } +">" { yylval.intval = GT; return(C_RELOP); } +"^" { return('^'); } +"|" { return('|'); } +"?" { return('?'); } +^#pragma[ \t].* { control(CPP_PRAGMA); } +^#ident[ \t].* { control(CPP_IDENT); } +^#line[ \t].* { control(CPP_LINE); } +^#.* { control(CPP_HASH); } + +[ \t\v\f] { } +"\n" { ++lineno; STABS_LINE(lineno); } +. { /* ignore bad characters */ } + +%% + +int lineno; +char *ftitle = "<stdin>"; + +int +yywrap(void) +{ + if (0) unput(0); /* quiet gcc */ + return(1); +} + +/* + * XXX floatcon() and fhexcon() should be in support libraries for + * the target floating point. + */ +static NODE * +f2(char *str) +{ + TWORD tw; + NODE *p; + double dc; + char *eptr; + + dc = strtod(str, &eptr); /* XXX - avoid strtod() */ + tw = (*eptr == 'f' || *eptr == 'F' ? FLOAT : DOUBLE); + p = block(FCON, NIL, NIL, tw, 0, MKSUE(tw)); + p->n_dcon = dc; + return p; +} + +NODE * +floatcon(void) +{ + return f2(yytext); +} + +static int +h2n(int ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + return ch - 'A' + 10; + +} + +NODE * +fhexcon(void) +{ + char buf[500]; + char *c = yytext; + unsigned long long num1, num2; + + /* XXX - convert it to a decimal float number and use strtod */ + c+= 2; /* skip 0x */ + for (num1 = 0; *c != '.' && *c != 'p' && *c != 'P'; c++) + num1 = (num1 << 4) | h2n(*c); + if (*c != '.' && *c != 'p' && *c != 'P') + cerror("fhexcon"); + num2 = 0; + if (*c == '.') { + c++; + for (; *c != 'p' && *c != 'P'; c++) + num2 = (num2 << 4) | h2n(*c); + } + if (*c != 'P' && *c != 'p') + cerror("fhexcon2"); + c++; + snprintf(buf, sizeof(buf), "%llu.%lluE%s", num1, num2, c); + return f2(buf); +} + +unsigned int +esccon(char **sptr) +{ + char *wr = *sptr; + unsigned int val; + + switch (*wr++) { + case 'a': val = '\a'; break; + case 'b': val = '\b'; break; + case 'f': val = '\f'; break; + case 'n': val = '\n'; break; + case 'r': val = '\r'; break; + case 't': val = '\t'; break; + case 'v': val = '\v'; break; + case '\"': val = '\"'; break; + case 'x': val = strtoul(wr, &wr, 16); break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + wr--; + val = strtoul(wr, &wr, 8); + break; + default: val = wr[-1]; + } + *sptr = wr; + return val; +} + +NODE * +cvtdig(int radix) +{ + NODE *p; + TWORD ntype; + unsigned long long v; + char *ch = yytext; + int n, numl, numu; + + if (radix == 16) + ch += 2; /* Skip 0x */ + + v = 0; + while ((*ch >= '0' && *ch <= '9') || (*ch >= 'a' && *ch <= 'f') || + (*ch >= 'A' && *ch <= 'F')) { + v *= radix; + n = *ch; + n = (n <= '9' ? n - '0' : (n > 'F' ? n - 'a' : n - 'A') + 10); + ch++; + v += n; + } + /* Parse trailing chars */ + ntype = INT; + numl = numu = 0; + for (n = 0; n < 3; n++) { + if (*ch == 0) + break; + if ((*ch == 'l' || *ch == 'L') && numl < 2) + ntype+=2, numl++; + else if ((*ch == 'u' || *ch == 'U') && numu < 1) + ntype = ENUNSIGN(ntype), numu++; + else + break; + ch++; + } + if (*ch) + uerror("constant has too many '%c'", *ch); + + if (ntype == INT) { + /* v contains a number. Get type correct */ + if (v > MAX_LONGLONG && radix != 10) + ntype = ULONGLONG; + else if (v > MAX_ULONG) + ntype = LONGLONG; + else if (v > MAX_LONG && radix != 10) + ntype = ULONG; + else if (v > MAX_UNSIGNED) + ntype = LONG; + else if (v > MAX_INT && radix != 10) + ntype = UNSIGNED; + } + ntype = ctype(ntype); + p = block(ICON, NIL, NIL, ntype, 0, MKSUE(ntype)); + p->n_lval = v; + ASGLVAL(p->n_slval, v); + + return p; +} + +/* + * Convert a character constant to an integer. + */ +NODE * +charcon(void) +{ + int lastcon = 0; + int val, i = 0; + char *pp = yytext; + + if (*pp == 'L') + pp++; + pp++; + while (*pp != '\'') { + if (*pp++ == '\\') { + val = esccon(&pp); + } else + val = pp[-1]; + makecc(val, i); + i++; + } + + if (i == 0) + uerror("empty character constant"); + if (i > (SZINT/SZCHAR) || (i>1)) + werror("too many characters in character constant"); + return bcon(lastcon); +} + +void +control(int t) +{ + char *wr = yytext; + char *eptr; + int val; + + wr++; /* Skip initial '#' */ + switch (t) { + case CPP_PRAGMA: + case CPP_IDENT: + return; /* Just skip these for now. */ + + case CPP_LINE: + wr += 4; + /* FALLTHROUGH */ + case CPP_HASH: + val = strtol(wr, &eptr, 10); + if (wr == eptr) /* Illegal string */ + goto bad; + wr = eptr; + lineno = val - 1; + while (*wr && *wr != '\"') + wr++; + if (*wr++ != '\"') + goto bad; + eptr = wr; + while (*wr && *wr != '\"') + wr++; + if (*wr != '\"') + goto bad; + *wr = 0; + ftitle = addstring(eptr); +#ifdef STABS + if (gflag) + stabs_file(ftitle); +#endif + } + return; +bad: + werror("%s: illegal control", yytext); +} diff --git a/usr.bin/pcc/ccom/stabs.c b/usr.bin/pcc/ccom/stabs.c new file mode 100644 index 00000000000..58ead7d986a --- /dev/null +++ b/usr.bin/pcc/ccom/stabs.c @@ -0,0 +1,374 @@ +/* $OpenBSD: stabs.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ + +/* + * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Simple implementation of the "stabs" debugging format. + * Not complete but at least makes it possible to set breakpoints, + * examine simple variables and do stack traces. + * Based on the stabs documentation that follows gdb. + */ + +#include "pass1.h" + +#ifdef STABS + +#include <sys/types.h> +#include <stab.h> +#include <stdarg.h> +#include <string.h> + +#define STABHASH 256 +#define INTNUM 1 /* internal number of type "int" */ +#define BIT2BYTE(x) ((x)/SZCHAR) + +#ifndef STABLBL +#error macdefs.h must define STABLBL +#endif + +/* + * Local type mapping + * Types are defined as a typeword, a dimension pointer (in the case + * of arrays) and struct/union/enum declarations. + * Function prototypes are ignored. + */ +static struct stabtype { + struct stabtype *next; /* linked list */ + TWORD type; /* pcc type number */ + union dimfun *df; /* dimension of arrays */ + struct suedef *sue; /* struct/union/enum declarations */ + int num; /* local type number */ +} *stabhash[STABHASH]; +static int ntypes; +static char *curfun; +static int stablbl = 10; + +void ptype(char *name, int num, int inhnum, long long min, long long max); +struct stabtype *addtype(TWORD, union dimfun *, struct suedef *); +struct stabtype *findtype(TWORD t, union dimfun *df, struct suedef *sue); +void printtype(struct symtab *s, char *str, int len); +void cprint(int p2, char *fmt, ...); + +#define MAXPSTR 100 + +extern int isinlining; +#define savestabs isinlining + +/* + * Output type definitions for the stab debugging format. + * Note that "int" is always internal number 1. + */ +void +stabs_init() +{ + struct stabtype *st; + +#define ADDTYPE(y) addtype(y, NULL, MKSUE(y)) + + ptype("int", ADDTYPE(INT)->num, INTNUM, MIN_INT, MAX_INT); + + st = ADDTYPE(CHAR); + ptype("char", st->num, st->num, 0, MAX_CHAR); + ptype("short", ADDTYPE(SHORT)->num, INTNUM, MIN_SHORT, MAX_SHORT); + ptype("long", ADDTYPE(LONG)->num, INTNUM, MIN_LONG, MAX_LONG); + ptype("long long", ADDTYPE(LONGLONG)->num, INTNUM, + MIN_LONGLONG, MAX_LONGLONG); + ptype("unsigned char", ADDTYPE(UCHAR)->num, INTNUM, 0, MAX_UCHAR); + ptype("unsigned short", ADDTYPE(USHORT)->num, INTNUM, 0, MAX_USHORT); + ptype("unsigned int", ADDTYPE(UNSIGNED)->num, INTNUM, 0, MAX_UNSIGNED); + ptype("unsigned long", ADDTYPE(ULONG)->num, INTNUM, 0, MAX_ULONG); + ptype("unsigned long long", ADDTYPE(ULONGLONG)->num, INTNUM, + 0, MAX_ULONGLONG); + + ptype("float", ADDTYPE(FLOAT)->num, INTNUM, 4, 0); + ptype("double", ADDTYPE(DOUBLE)->num, INTNUM, 8, 0); + ptype("long double", ADDTYPE(LDOUBLE)->num, INTNUM, 12, 0); + st = ADDTYPE(VOID); + cprint(savestabs, ".stabs \"void:t%d=r%d\",%d,0,0,0\n", + st->num, st->num, N_LSYM); + +} + +/* + * Print a type in stabs format + */ +void +ptype(char *name, int num, int inhnum, long long min, long long max) +{ + cprint(savestabs, ".stabs \"%s:t%d=r%d;%lld;%lld;\",%d,0,0,0", + name, num, inhnum, min, max, N_LSYM); +} + +/* + * Add a new local type to the hash table. + * The search key is the (type, df, sue) triple. + */ +struct stabtype * +addtype(TWORD t, union dimfun *df, struct suedef *sue) +{ + struct stabtype *st; + + st = permalloc(sizeof(struct stabtype)); + st->type = t; + st->df = df; + st->sue = sue; + st->num = ++ntypes; + st->next = stabhash[t & (STABHASH-1)]; + stabhash[t & (STABHASH-1)] = st; + return st; +} + +/* + * Search for a given type and return a type pointer (or NULL). + */ +struct stabtype * +findtype(TWORD t, union dimfun *df, struct suedef *sue) +{ + struct stabtype *st; + union dimfun *dw, *dx; + TWORD tw; + + st = stabhash[t & (STABHASH-1)]; + for (; st; st = st->next) { + if (t != st->type || sue != st->sue) + continue; + /* Ok, type and sue matches, check dimensions */ + if (st->df == NULL) + return st; /* no arrays, got match */ + dw = st->df; + dx = df; + tw = t; + for (; tw > BTMASK; tw = DECREF(tw)) { + if (ISARY(tw)) { + if (dw->ddim == dx->ddim) + dw++, dx++; + else + break; + } + } + if (tw <= BTMASK) + return st; + } + return NULL; +} + +/* + * Print current line number. + */ +void +stabs_line(int line) +{ + cprint(savestabs, ".stabn %d,0,%d," STABLBL "-%s", N_SLINE, line, stablbl, curfun); + cprint(1, STABLBL ":", stablbl++); +} + +/* + * Start of block. + */ +void +stabs_lbrac(int blklvl) +{ + cprint(savestabs, ".stabn %d,0,%d," STABLBL "-%s", + N_LBRAC, blklvl, stablbl, curfun); + cprint(1, STABLBL ":", stablbl++); +} + +/* + * End of block. + */ +void +stabs_rbrac(int blklvl) +{ + cprint(savestabs, ".stabn %d,0,%d," STABLBL "-%s\n", + N_RBRAC, blklvl, stablbl, curfun); + cprint(1, STABLBL ":", stablbl++); +} + +/* + * Print current file and set mark. + */ +void +stabs_file(char *fname) +{ + static char *mainfile; + + if (mainfile == NULL) + mainfile = fname; /* first call */ + cprint(savestabs, ".stabs \"%s\",%d,0,0," STABLBL, + fname, fname == mainfile ? N_SO : N_SOL, stablbl); + cprint(savestabs, STABLBL ":", stablbl++); +} + +/* + * Print beginning of function. + */ +void +stabs_func(struct symtab *s) +{ + char str[MAXPSTR]; + + curfun = s->sname; +#ifdef GCC_COMPAT + curfun = gcc_findname(cftnsp); +#endif + printtype(s, str, sizeof(str)); + cprint(savestabs, ".stabs \"%s:%c%s\",%d,0,%d,%s", + curfun, s->sclass == STATIC ? 'f' : 'F', str, + N_FUN, BIT2BYTE(s->ssue->suesize), exname(curfun)); +} + +/* + * Print a (complex) type. + * Will also create subtypes. + * Printed string is like "20=*21=*1". + */ +void +printtype(struct symtab *s, char *ostr, int len) +{ + struct stabtype *st; + union dimfun *df = s->sdf; + struct suedef *sue = s->ssue; + TWORD t = s->stype; + int op = 0; + + /* Print out not-yet-found types */ + if (ISFTN(t)) + t = DECREF(t); + st = findtype(t, df, sue); + while (st == NULL && t > BTMASK) { + st = addtype(t, df, sue); + op+=snprintf(ostr+op, len - op, "%d=", st->num); + if (ISFTN(t)) + ostr[op++] = 'f'; + else if (ISPTR(t)) + ostr[op++] = '*'; + else if (ISARY(t)) { + op+=snprintf(ostr+op, len - op, "ar%d;0;%d;", INTNUM, df->ddim-1); + } else + cerror("printtype: notype"); + if (ISARY(t)) + df++; + t = DECREF(t); + st = findtype(t, df, sue); + if (op > MAXPSTR-10) + cerror("printtype: too difficult expression"); + } + /* print out basic type. may have to be entered in case of sue */ + snprintf(ostr+op, len - op, "%d", st == NULL ? 1 : st->num); + /* snprintf here null-terminated the string */ +} + +void +stabs_newsym(struct symtab *s) +{ + char *sname; + char ostr[MAXPSTR]; + + if (ISFTN(s->stype)) + return; /* functions are handled separate */ + + if (s->sclass == STNAME || s->sclass == UNAME || s->sclass == MOS || + s->sclass == ENAME || s->sclass == MOU || s->sclass == MOE || + s->sclass == TYPEDEF || (s->sclass & FIELD)) + return; /* XXX - fix structs */ + + sname = s->sname; +#ifdef GCC_COMPAT + sname = gcc_findname(s); +#endif + + printtype(s, ostr, sizeof(ostr)); + switch (s->sclass) { + case PARAM: + cprint(savestabs, ".stabs \"%s:p%s\",%d,0,%d,%d", sname, ostr, + N_PSYM, BIT2BYTE(s->ssue->suesize), BIT2BYTE(s->soffset)); + break; + + case AUTO: + cprint(savestabs, ".stabs \"%s:%s\",%d,0,%d,%d", sname, ostr, + N_LSYM, BIT2BYTE(s->ssue->suesize), BIT2BYTE(s->soffset)); + break; + + case STATIC: + if (blevel) + cprint(savestabs, ".stabs \"%s:V%s\",%d,0,%d," LABFMT, sname, ostr, + N_LCSYM, BIT2BYTE(s->ssue->suesize), s->soffset); + else + cprint(savestabs, ".stabs \"%s:S%s\",%d,0,%d,%s", sname, ostr, + N_LCSYM, BIT2BYTE(s->ssue->suesize), exname(sname)); + break; + + case EXTERN: + case EXTDEF: + cprint(savestabs, ".stabs \"%s:G%s\",%d,0,%d,0", sname, ostr, + N_GSYM, BIT2BYTE(s->ssue->suesize)); + break; + + case REGISTER: + cprint(savestabs, ".stabs \"%s:r%s\",%d,0,%d,%d", sname, ostr, + N_RSYM, 1, s->soffset); + break; + + default: + cerror("fix stab_newsym; class %d", s->sclass); + } +} + +void +stabs_chgsym(struct symtab *s) +{ +} + +/* + * define a struct. + */ +void +stabs_struct(struct symtab *p, struct suedef *sue) +{ +} + +void +cprint(int p2, char *fmt, ...) +{ + va_list ap; + char *str; + + va_start(ap, fmt); + if (p2) { + str = tmpvsprintf(fmt, ap); + str = newstring(str, strlen(str)); /* XXX - for inlines */ + send_passt(IP_ASM, str); + } else { + putchar('\t'); + vprintf(fmt, ap); + putchar('\n'); + } + va_end(ap); +} + +#endif diff --git a/usr.bin/pcc/ccom/symtabs.c b/usr.bin/pcc/ccom/symtabs.c new file mode 100644 index 00000000000..97dd715375a --- /dev/null +++ b/usr.bin/pcc/ccom/symtabs.c @@ -0,0 +1,356 @@ +/* $OpenBSD: symtabs.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "pass1.h" + +/* + * These definitions are used in the patricia tree that stores + * the strings. + */ +#define LEFT_IS_LEAF 0x80000000 +#define RIGHT_IS_LEAF 0x40000000 +#define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0) +#define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0) +#define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF)) +#define CHECKBITS 8 + +struct tree { + int bitno; + struct tree *lr[2]; +}; + +static struct tree *firstname; +int nametabs, namestrlen; +static struct tree *firststr; +int strtabs, strstrlen; +static char *symtab_add(char *key, struct tree **, int *, int *); + +#define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1 +#define getree() permalloc(sizeof(struct tree)) + +char * +addname(char *key) +{ + return symtab_add(key, &firstname, &nametabs, &namestrlen); +} + +char * +addstring(char *key) +{ + return symtab_add(key, &firststr, &strtabs, &strstrlen); +} + +/* + * Add a name to the name stack (if its non-existing), + * return its address. + * This is a simple patricia implementation. + */ +char * +symtab_add(char *key, struct tree **first, int *tabs, int *stlen) +{ + struct tree *w, *new, *last; + int cix, bit, fbit, svbit, ix, bitno, len; + char *m, *k, *sm; + + /* Count full string length */ + for (k = key, len = 0; *k; k++, len++) + ; + + switch (*tabs) { + case 0: + *first = (struct tree *)newstring(key, len); + *stlen += (len + 1); + (*tabs)++; + return (char *)*first; + + case 1: + m = (char *)*first; + svbit = 0; /* XXX why? */ + break; + + default: + w = *first; + bitno = len * CHECKBITS; + for (;;) { + bit = BITNO(w->bitno); + fbit = bit > bitno ? 0 : P_BIT(key, bit); + svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : + IS_LEFT_LEAF(w->bitno); + w = w->lr[fbit]; + if (svbit) { + m = (char *)w; + break; + } + } + } + + sm = m; + k = key; + + /* Check for correct string and return */ + for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS) + ; + if (*m == 0 && *k == 0) + return sm; + + ix = *m ^ *k; + while ((ix & 1) == 0) + ix >>= 1, cix++; + + /* Create new node */ + new = getree(); + bit = P_BIT(key, cix); + new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + new->lr[bit] = (struct tree *)newstring(key, len); + *stlen += (len + 1); + + if ((*tabs)++ == 1) { + new->lr[!bit] = *first; + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + *first = new; + return (char *)new->lr[bit]; + } + + + w = *first; + last = NULL; + for (;;) { + fbit = w->bitno; + bitno = BITNO(w->bitno); + if (bitno == cix) + cerror("bitno == cix"); + if (bitno > cix) + break; + svbit = P_BIT(key, bitno); + last = w; + w = w->lr[svbit]; + if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) + break; + } + + new->lr[!bit] = w; + if (last == NULL) { + *first = new; + } else { + last->lr[svbit] = new; + last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + } + if (bitno < cix) + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + return (char *)new->lr[bit]; +} + +static struct tree *sympole[NSTYPES]; +static struct symtab *tmpsyms[NSTYPES]; +int numsyms[NSTYPES]; + +/* + * Inserts a symbol into the symbol tree. + * Returns a struct symtab. + */ +struct symtab * +lookup(char *key, int ttype) +{ + struct symtab *sym; + struct tree *w, *new, *last; + int cix, bit, fbit, svbit, ix, bitno, match; + int type, uselvl; + + long code = (long)key; + type = ttype & SMASK; + uselvl = (blevel > 0 && type != SSTRING); + + /* + * The local symbols are kept in a simple linked list. + * Check this list first. + */ + if (blevel > 0) + for (sym = tmpsyms[type]; sym; sym = sym->snext) + if (sym->sname == key) + return sym; + + switch (numsyms[type]) { + case 0: + if (ttype & SNOCREAT) + return NULL; + if (uselvl) { + sym = getsymtab(key, ttype|STEMP); + sym->snext = tmpsyms[type]; + tmpsyms[type] = sym; + return sym; + } + sympole[type] = (struct tree *)getsymtab(key, ttype); + numsyms[type]++; + return (struct symtab *)sympole[type]; + + case 1: + w = (struct tree *)sympole[type]; + svbit = 0; /* XXX why? */ + break; + + default: + w = sympole[type]; + for (;;) { + bit = BITNO(w->bitno); + fbit = (code >> bit) & 1; + svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : + IS_LEFT_LEAF(w->bitno); + w = w->lr[fbit]; + if (svbit) + break; + } + } + + sym = (struct symtab *)w; + match = (long)sym->sname; + + ix = code ^ match; + if (ix == 0) + return sym; + else if (ttype & SNOCREAT) + return NULL; + +#ifdef PCC_DEBUG + if (ddebug) + printf(" adding %s as %s at level %d\n", + key, uselvl ? "temp" : "perm", blevel); +#endif + + /* + * Insert into the linked list, if feasible. + */ + if (uselvl) { + sym = getsymtab(key, ttype|STEMP); + sym->snext = tmpsyms[type]; + tmpsyms[type] = sym; + return sym; + } + + /* + * Need a new node. If type is SNORMAL and inside a function + * the node must be allocated as permanent anyway. + * This could be optimized by adding a remove routine, but it + * may be more trouble than it is worth. + */ + if (ttype == (STEMP|SNORMAL)) + ttype = SNORMAL; + + for (cix = 0; (ix & 1) == 0; ix >>= 1, cix++) + ; + + new = ttype & STEMP ? tmpalloc(sizeof(struct tree)) : + permalloc(sizeof(struct tree)); + bit = (code >> cix) & 1; + new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + new->lr[bit] = (struct tree *)getsymtab(key, ttype); + if (numsyms[type]++ == 1) { + new->lr[!bit] = sympole[type]; + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + sympole[type] = new; + return (struct symtab *)new->lr[bit]; + } + + + w = sympole[type]; + last = NULL; + for (;;) { + fbit = w->bitno; + bitno = BITNO(w->bitno); + if (bitno == cix) + cerror("bitno == cix"); + if (bitno > cix) + break; + svbit = (code >> bitno) & 1; + last = w; + w = w->lr[svbit]; + if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) + break; + } + + new->lr[!bit] = w; + if (last == NULL) { + sympole[type] = new; + } else { + last->lr[svbit] = new; + last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + } + if (bitno < cix) + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + return (struct symtab *)new->lr[bit]; +} + +void +symclear(int level) +{ + struct symtab *s; + int i; + +#ifdef PCC_DEBUG + if (ddebug) + printf("symclear(%d)\n", level); +#endif + if (level < 1) { + for (i = 0; i < NSTYPES; i++) { + s = tmpsyms[i]; + tmpsyms[i] = 0; + if (i != SLBLNAME) + continue; + while (s != NULL) { + if (s->soffset < 0) + uerror("label '%s' undefined",s->sname); + s = s->snext; + } + } + } else { + for (i = 0; i < NSTYPES; i++) { + if (i == SLBLNAME) + continue; /* function scope */ + while (tmpsyms[i] != NULL && + tmpsyms[i]->slevel > level) { + tmpsyms[i] = tmpsyms[i]->snext; + } + } + } +} + +struct symtab * +hide(struct symtab *sym) +{ + struct symtab *new; + + new = getsymtab(sym->sname, SNORMAL|STEMP); + new->snext = tmpsyms[SNORMAL]; + tmpsyms[SNORMAL] = new; +#ifdef PCC_DEBUG + if (ddebug) + printf("\t%s hidden at level %d (%p -> %p)\n", + sym->sname, blevel, sym, new); +#endif + return new; +} diff --git a/usr.bin/pcc/ccom/trees.c b/usr.bin/pcc/ccom/trees.c new file mode 100644 index 00000000000..077d4b9d743 --- /dev/null +++ b/usr.bin/pcc/ccom/trees.c @@ -0,0 +1,2466 @@ +/* $Id: trees.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Some of the changes from 32V include: + * - Understand "void" as type. + * - Handle enums as ints everywhere. + * - Convert some C-specific ops into branches. + */ + +# include "pass1.h" +# include "pass2.h" + +# include <stdarg.h> + +static void chkpun(NODE *p); +static int chkenum(int, int, NODE *p); +static int opact(NODE *p); +static int moditype(TWORD); +static NODE *strargs(NODE *); +static void rmcops(NODE *p); + +int lastloc = -1; + +/* some special actions, used in finding the type of nodes */ +# define NCVT 01 +# define PUN 02 +# define TYPL 04 +# define TYPR 010 +# define TYMATCH 040 +# define LVAL 0100 +# define CVTO 0200 +# define CVTL 0400 +# define CVTR 01000 +# define PTMATCH 02000 +# define OTHER 04000 +# define NCVTR 010000 + +/* node conventions: + + NAME: rval>0 is stab index for external + rval<0 is -inlabel number + lval is offset in bits + ICON: lval has the value + rval has the STAB index, or - label number, + if a name whose address is in the constant + rval = NONAME means no name + REG: rval is reg. identification cookie + + */ + +int bdebug = 0; + +NODE * +buildtree(int o, NODE *l, NODE *r) +{ + NODE *p, *q; + int actions; + int opty; + struct symtab *sp = NULL; /* XXX gcc */ + NODE *lr, *ll; + char *name; + struct symtab **elem; + +#ifdef PCC_DEBUG + if (bdebug) { + printf("buildtree(%s, %p, %p)\n", copst(o), l, r); + if (l) fwalk(l, eprint, 0); + if (r) fwalk(r, eprint, 0); + } +#endif + opty = coptype(o); + + /* check for constants */ + + if( opty == UTYPE && l->n_op == ICON ){ + + switch( o ){ + + case NOT: + case UMINUS: + case COMPL: + if( conval( l, o, l ) ) return(l); + break; + } + } else if (o == NOT && l->n_op == FCON) { + l = clocal(block(SCONV, l, NIL, INT, 0, MKSUE(INT))); + } else if( o == UMINUS && l->n_op == FCON ){ + l->n_dcon = -l->n_dcon; + return(l); + + } else if( o==QUEST && l->n_op==ICON ) { + CONSZ c = l->n_lval; + nfree(l); + if (c) { + tfree(r->n_right); + l = r->n_left; + nfree(r); + return(l); + } else { + tfree(r->n_left); + l = r->n_right; + nfree(r); + return(l); + } + } else if( opty == BITYPE && l->n_op == ICON && r->n_op == ICON ){ + + switch( o ){ + + case PLUS: + case MINUS: + case MUL: + case DIV: + case MOD: + /* + * Do type propagation for simple types here. + * The constant value is correct anyway. + * Maybe this op shortcut should be removed? + */ + if (l->n_sp == NULL && r->n_sp == NULL && + l->n_type < BTMASK && r->n_type < BTMASK) { + if (l->n_type > r->n_type) + r->n_type = l->n_type; + else + l->n_type = r->n_type; + } + /* FALLTHROUGH */ + case ULT: + case UGT: + case ULE: + case UGE: + case LT: + case GT: + case LE: + case GE: + case EQ: + case NE: + case ANDAND: + case OROR: + case AND: + case OR: + case ER: + case LS: + case RS: + if( conval( l, o, r ) ) { + nfree(r); + return(l); + } + break; + } + } else if (opty == BITYPE && (l->n_op == FCON || l->n_op == ICON) && + (r->n_op == FCON || r->n_op == ICON) && (o == PLUS || o == MINUS || + o == MUL || o == DIV)) { + switch(o){ + case PLUS: + case MINUS: + case MUL: + case DIV: + if (l->n_op == ICON) + l->n_dcon = l->n_lval; + if (r->n_op == ICON) + r->n_dcon = r->n_lval; + switch (o) { + case PLUS: + l->n_dcon += r->n_dcon; break; + case MINUS: + l->n_dcon -= r->n_dcon; break; + case MUL: + l->n_dcon *= r->n_dcon; break; + case DIV: + if (r->n_dcon == 0) + uerror("division by 0."); + else + l->n_dcon /= r->n_dcon; + } + l->n_op = FCON; + l->n_type = DOUBLE; + l->n_sue = MKSUE(DOUBLE); + nfree(r); + return(l); + } + } + + /* its real; we must make a new node */ + + p = block(o, l, r, INT, 0, MKSUE(INT)); + + actions = opact(p); + + if (actions & LVAL) { /* check left descendent */ + if (notlval(p->n_left)) { + uerror("lvalue required"); +#ifdef notyet + } else { + if ((l->n_type > BTMASK && ISCON(l->n_qual)) || + (l->n_type <= BTMASK && ISCON(l->n_qual << TSHIFT))) + if (blevel > 0) + uerror("lvalue is declared const"); +#endif + } + } + + if( actions & NCVTR ){ + p->n_left = pconvert( p->n_left ); + } + else if( !(actions & NCVT ) ){ + switch( opty ){ + + case BITYPE: + p->n_right = pconvert( p->n_right ); + case UTYPE: + p->n_left = pconvert( p->n_left ); + + } + } + + if ((actions&PUN) && (o!=CAST)) + chkpun(p); + + if( actions & (TYPL|TYPR) ){ + + q = (actions&TYPL) ? p->n_left : p->n_right; + + p->n_type = q->n_type; + p->n_qual = q->n_qual; + p->n_df = q->n_df; + p->n_sue = q->n_sue; + } + + if( actions & CVTL ) p = convert( p, CVTL ); + if( actions & CVTR ) p = convert( p, CVTR ); + if( actions & TYMATCH ) p = tymatch(p); + if( actions & PTMATCH ) p = ptmatch(p); + + if( actions & OTHER ){ + l = p->n_left; + r = p->n_right; + + switch(o){ + + case NAME: + sp = spname; + if (sp->sflags & STNODE) { + /* Generated for optimizer */ + p->n_op = TEMP; + p->n_type = sp->stype; + p->n_sue = sp->ssue; + p->n_df = sp->sdf; + p->n_lval = sp->soffset; + break; + } + +#ifdef GCC_COMPAT + /* Get a label name */ + if (sp->sflags == SLBLNAME) { + p->n_type = VOID; + p->n_sue = MKSUE(VOID); + p->n_lval = 0; + p->n_sp = sp; + break; + } else +#endif + if (sp->stype == UNDEF) { + uerror("%s undefined", sp->sname); + /* make p look reasonable */ + p->n_type = INT; + p->n_sue = MKSUE(INT); + p->n_df = NULL; + p->n_sp = sp; + p->n_lval = 0; + defid(p, SNULL); + break; + } + p->n_type = sp->stype; + p->n_qual = sp->squal; + p->n_df = sp->sdf; + p->n_sue = sp->ssue; + p->n_lval = 0; + p->n_sp = sp; + /* special case: MOETY is really an ICON... */ + if (p->n_type == MOETY) { + p->n_sp = NULL; + p->n_lval = sp->soffset; + p->n_df = NULL; + p->n_type = ENUMTY; + p->n_op = ICON; + } + break; + + case STREF: + /* p->x turned into *(p+offset) */ + /* rhs must be a name; check correctness */ + + /* Find member symbol struct */ + if (l->n_type != PTR+STRTY && l->n_type != PTR+UNIONTY){ + uerror("struct or union required"); + break; + } + + if ((elem = l->n_sue->suelem) == NULL) + uerror("undefined struct or union"); + + name = r->n_name; + for (; *elem != NULL; elem++) { + sp = *elem; + if (sp->sname == name) + break; + } + if (*elem == NULL) + uerror("member '%s' not declared", name); + + r->n_sp = sp; + p = stref(p); + break; + + case UMUL: + if (l->n_op == ADDROF) { + nfree(p); + p = l->n_left; + nfree(l); + } + if( !ISPTR(l->n_type))uerror("illegal indirection"); + p->n_type = DECREF(l->n_type); + p->n_qual = DECREF(l->n_qual); + p->n_df = l->n_df; + p->n_sue = l->n_sue; + break; + + case ADDROF: + switch( l->n_op ){ + + case UMUL: + nfree(p); + p = l->n_left; + nfree(l); + case TEMP: + case NAME: + p->n_type = INCREF(l->n_type); + p->n_qual = INCQAL(l->n_qual); + p->n_df = l->n_df; + p->n_sue = l->n_sue; + break; + + case COMOP: + nfree(p); + lr = buildtree(ADDROF, l->n_right, NIL); + p = buildtree( COMOP, l->n_left, lr ); + nfree(l); + break; + + case QUEST: + lr = buildtree( ADDROF, l->n_right->n_right, NIL ); + ll = buildtree( ADDROF, l->n_right->n_left, NIL ); + nfree(p); nfree(l->n_right); + p = buildtree( QUEST, l->n_left, buildtree( COLON, ll, lr ) ); + nfree(l); + break; + + default: + uerror("unacceptable operand of &: %d", l->n_op ); + break; + } + break; + + case LS: + case RS: /* must make type size at least int... */ + if (p->n_type == CHAR || p->n_type == SHORT) { + p->n_left = makety(l, INT, 0, 0, MKSUE(INT)); + } else if (p->n_type == UCHAR || p->n_type == USHORT) { + p->n_left = makety(l, UNSIGNED, 0, 0, + MKSUE(UNSIGNED)); + } + l = p->n_left; + p->n_type = l->n_type; + p->n_qual = l->n_qual; + p->n_df = l->n_df; + p->n_sue = l->n_sue; + + /* FALLTHROUGH */ + case LSEQ: + case RSEQ: /* ...but not for assigned types */ + if(tsize(r->n_type, r->n_df, r->n_sue) > SZINT) + p->n_right = makety(r, INT, 0, 0, MKSUE(INT)); + break; + + case RETURN: + case ASSIGN: + case CAST: + /* structure assignment */ + /* take the addresses of the two sides; then make an + * operator using STASG and + * the addresses of left and right */ + + { + struct suedef *sue; + TWORD t; + union dimfun *d; + + if (l->n_sue != r->n_sue) + uerror("assignment of different structures"); + + r = buildtree(ADDROF, r, NIL); + t = r->n_type; + d = r->n_df; + sue = r->n_sue; + + l = block(STASG, l, r, t, d, sue); + + if( o == RETURN ){ + nfree(p); + p = l; + break; + } + + p->n_op = UMUL; + p->n_left = l; + p->n_right = NIL; + break; + } + case COLON: + /* structure colon */ + + if (l->n_sue != r->n_sue) + uerror( "type clash in conditional" ); + break; + + case CALL: + p->n_right = r = strargs(p->n_right); + case UCALL: + if (!ISPTR(l->n_type)) + uerror("illegal function"); + p->n_type = DECREF(l->n_type); + if (!ISFTN(p->n_type)) + uerror("illegal function"); + p->n_type = DECREF(p->n_type); + p->n_df = l->n_df; + p->n_sue = l->n_sue; + if (l->n_op == ADDROF && l->n_left->n_op == NAME && + l->n_left->n_sp != NULL && l->n_left->n_sp != NULL && + (l->n_left->n_sp->sclass == FORTRAN || + l->n_left->n_sp->sclass == UFORTRAN)) { + p->n_op += (FORTCALL-CALL); + } + if (p->n_type == STRTY || p->n_type == UNIONTY) { + /* function returning structure */ + /* make function really return ptr to str., with * */ + + p->n_op += STCALL-CALL; + p->n_type = INCREF(p->n_type); + p = clocal(p); /* before recursing */ + p = buildtree(UMUL, p, NIL); + + } + break; + + default: + cerror( "other code %d", o ); + } + + } + + /* + * Allow (void)0 casts. + * XXX - anything on the right side must be possible to cast. + * XXX - remove void types further on. + */ + if (p->n_op == CAST && p->n_type == VOID && + p->n_right->n_op == ICON) + p->n_right->n_type = VOID; + + if (actions & CVTO) + p = oconvert(p); + p = clocal(p); + +#ifdef PCC_DEBUG + if (bdebug) { + printf("End of buildtree:\n"); + fwalk(p, eprint, 0); + } +#endif + + return(p); + + } + +/* + * Do a conditional branch. + */ +void +cbranch(NODE *p, NODE *q) +{ + p = buildtree(CBRANCH, p, q); + if (p->n_left->n_op == ICON) { + if (p->n_left->n_lval != 0) + branch(q->n_lval); /* branch always */ + tfree(p); + tfree(q); + return; + } + ecomp(p); +} + +NODE * +strargs( p ) register NODE *p; { /* rewrite structure flavored arguments */ + + if( p->n_op == CM ){ + p->n_left = strargs( p->n_left ); + p->n_right = strargs( p->n_right ); + return( p ); + } + + if( p->n_type == STRTY || p->n_type == UNIONTY ){ + p = block(STARG, p, NIL, p->n_type, p->n_df, p->n_sue); + p->n_left = buildtree( ADDROF, p->n_left, NIL ); + p = clocal(p); + } + return( p ); +} + +/* + * apply the op o to the lval part of p; if binary, rhs is val + */ +int +conval(NODE *p, int o, NODE *q) +{ + int i, u; + CONSZ val; + U_CONSZ v1, v2; + + val = q->n_lval; + u = ISUNSIGNED(p->n_type) || ISUNSIGNED(q->n_type); + if( u && (o==LE||o==LT||o==GE||o==GT)) o += (UGE-GE); + + if (p->n_sp != NULL && q->n_sp != NULL) + return(0); + if (q->n_sp != NULL && o != PLUS) + return(0); + if (p->n_sp != NULL && o != PLUS && o != MINUS) + return(0); + v1 = p->n_lval; + v2 = q->n_lval; + switch( o ){ + + case PLUS: + p->n_lval += val; + if (p->n_sp == NULL) { + p->n_rval = q->n_rval; + p->n_type = q->n_type; + } + break; + case MINUS: + p->n_lval -= val; + break; + case MUL: + p->n_lval *= val; + break; + case DIV: + if (val == 0) + uerror("division by 0"); + else { + if (u) { + v1 /= v2; + p->n_lval = v1; + } else + p->n_lval /= val; + } + break; + case MOD: + if (val == 0) + uerror("division by 0"); + else { + if (u) { + v1 %= v2; + p->n_lval = v1; + } else + p->n_lval %= val; + } + break; + case AND: + p->n_lval &= val; + break; + case OR: + p->n_lval |= val; + break; + case ER: + p->n_lval ^= val; + break; + case LS: + i = val; + p->n_lval = p->n_lval << i; + break; + case RS: + i = val; + if (u) { + v1 = v1 >> i; + p->n_lval = v1; + } else + p->n_lval = p->n_lval >> i; + break; + + case UMINUS: + p->n_lval = - p->n_lval; + break; + case COMPL: + p->n_lval = ~p->n_lval; + break; + case NOT: + p->n_lval = !p->n_lval; + break; + case LT: + p->n_lval = p->n_lval < val; + break; + case LE: + p->n_lval = p->n_lval <= val; + break; + case GT: + p->n_lval = p->n_lval > val; + break; + case GE: + p->n_lval = p->n_lval >= val; + break; + case ULT: + p->n_lval = v1 < v2; + break; + case ULE: + p->n_lval = v1 <= v2; + break; + case UGT: + p->n_lval = v1 > v2; + break; + case UGE: + p->n_lval = v1 >= v2; + break; + case EQ: + p->n_lval = p->n_lval == val; + break; + case NE: + p->n_lval = p->n_lval != val; + break; + case ANDAND: + p->n_lval = p->n_lval && val; + break; + case OROR: + p->n_lval = p->n_lval || val; + break; + default: + return(0); + } + return(1); + } + +/* + * Checks p for the existance of a pun. This is called when the op of p + * is ASSIGN, RETURN, CAST, COLON, or relational. + * One case is when enumerations are used: this applies only to lint. + * In the other case, one operand is a pointer, the other integer type + * we check that this integer is in fact a constant zero... + * in the case of ASSIGN, any assignment of pointer to integer is illegal + * this falls out, because the LHS is never 0. + */ +void +chkpun(NODE *p) +{ + union dimfun *d1, *d2; + NODE *q; + int t1, t2; + + t1 = p->n_left->n_type; + t2 = p->n_right->n_type; + + switch (p->n_op) { + case RETURN: + /* return of void allowed but nothing else */ + if (t1 == VOID && t2 == VOID) + return; + if (t1 == VOID) { + werror("returning value from void function"); + return; + } + if (t2 == VOID) { + uerror("using void value"); + return; + } + case COLON: + if (t1 == VOID && t2 == VOID) + return; + break; + default: + if ((t1 == VOID && t2 != VOID) || (t1 != VOID && t2 == VOID)) { + uerror("value of void expression used"); + return; + } + break; + } + + /* allow void pointer assignments in any direction */ + if (BTYPE(t1) == VOID && (t2 & TMASK)) + return; + if (BTYPE(t2) == VOID && (t1 & TMASK)) + return; + + /* check for enumerations */ + if (t1 == ENUMTY || t2 == ENUMTY) { + if (clogop(p->n_op) && p->n_op != EQ && p->n_op != NE) { + werror("comparison of enums"); + return; + } + if (chkenum(t1, t2, p)) + return; + } + + if (ISPTR(t1) || ISARY(t1)) + q = p->n_right; + else + q = p->n_left; + + if (!ISPTR(q->n_type) && !ISARY(q->n_type)) { + if (q->n_op != ICON || q->n_lval != 0) + werror("illegal combination of pointer and integer"); + } else { + d1 = p->n_left->n_df; + d2 = p->n_right->n_df; + if (t1 == t2) { + if (p->n_left->n_sue != p->n_right->n_sue) + werror("illegal structure pointer combination"); + return; + } + for (;;) { + if (ISARY(t1) || ISPTR(t1)) { + if (!ISARY(t2) && !ISPTR(t2)) + break; + if (ISARY(t1) && ISARY(t2) && d1->ddim != d2->ddim) { + werror("illegal array size combination"); + return; + } + if (ISARY(t1)) + ++d1; + if (ISARY(t2)) + ++d2; + } else if (ISFTN(t1)) { + if (chkftn(d1->dfun, d2->dfun)) { + werror("illegal function " + "pointer combination"); + return; + } + ++d1; + ++d2; + } else if (t1 == ENUMTY || t2 == ENUMTY) { + chkenum(t1, t2, p); + return; + } else + break; + t1 = DECREF(t1); + t2 = DECREF(t2); + } + werror("illegal pointer combination"); + } +} + +static int +chkenum(int t1, int t2, NODE *p) +{ + if (t1 == ENUMTY && t2 == ENUMTY) { + if (p->n_left->n_sue != p->n_right->n_sue) + werror("enumeration type clash, operator %s", copst(p->n_op)); + return 1; + } + if ((t1 == ENUMTY && !(t2 >= CHAR && t2 <= UNSIGNED)) || + (t2 == ENUMTY && !(t1 >= CHAR && t1 <= UNSIGNED))) { + werror("illegal combination of enum and non-integer type"); + return 1; + } + return 0; +} + +NODE * +stref(NODE *p) +{ + NODE *r; + struct suedef *sue; + union dimfun *d; + TWORD t, q; + int dsc; + OFFSZ off; + struct symtab *s; + + /* make p->x */ + /* this is also used to reference automatic variables */ + + s = p->n_right->n_sp; + nfree(p->n_right); + r = p->n_left; + nfree(p); + p = pconvert(r); + + /* make p look like ptr to x */ + + if (!ISPTR(p->n_type)) + p->n_type = PTR+UNIONTY; + + t = INCREF(s->stype); + q = INCQAL(s->squal); + d = s->sdf; + sue = s->ssue; + + p = makety(p, t, q, d, sue); + + /* compute the offset to be added */ + + off = s->soffset; + dsc = s->sclass; + + if (dsc & FIELD) { /* make fields look like ints */ + off = (off/ALINT)*ALINT; + sue = MKSUE(INT); + } + if (off != 0) { + p = block(PLUS, p, offcon(off, t, d, sue), t, d, sue); + p->n_qual = q; + p = optim(p); + } + + p = buildtree(UMUL, p, NIL); + + /* if field, build field info */ + + if (dsc & FIELD) { + p = block(FLD, p, NIL, s->stype, 0, s->ssue); + p->n_qual = q; + p->n_rval = PKFIELD(dsc&FLDSIZ, s->soffset%ALINT); + } + + p = clocal(p); + return p; +} + +int +notlval(p) register NODE *p; { + + /* return 0 if p an lvalue, 1 otherwise */ + + again: + + switch( p->n_op ){ + + case FLD: + p = p->n_left; + goto again; + + case NAME: + case OREG: + case UMUL: + if( ISARY(p->n_type) || ISFTN(p->n_type) ) return(1); + case TEMP: + case REG: + return(0); + + default: + return(1); + + } + + } +/* make a constant node with value i */ +NODE * +bcon(int i) +{ + register NODE *p; + + p = block(ICON, NIL, NIL, INT, 0, MKSUE(INT)); + p->n_lval = i; + p->n_sp = NULL; + return(clocal(p)); +} + +NODE * +bpsize(NODE *p) +{ + return(offcon(psize(p), p->n_type, p->n_df, p->n_sue)); +} + +/* + * p is a node of type pointer; psize returns the + * size of the thing pointed to + */ +OFFSZ +psize(NODE *p) +{ + + if (!ISPTR(p->n_type)) { + uerror("pointer required"); + return(SZINT); + } + /* note: no pointers to fields */ + return(tsize(DECREF(p->n_type), p->n_df, p->n_sue)); +} + +/* + * convert an operand of p + * f is either CVTL or CVTR + * operand has type int, and is converted by the size of the other side + * convert is called when an integer is to be added to a pointer, for + * example in arrays or structures. + */ +NODE * +convert(NODE *p, int f) +{ + union dimfun *df; + TWORD ty, ty2; + NODE *q, *r, *s, *rv; + + if (f == CVTL) { + q = p->n_left; + s = p->n_right; + } else { + q = p->n_right; + s = p->n_left; + } + ty2 = ty = DECREF(s->n_type); + while (ISARY(ty)) + ty = DECREF(ty); + + r = offcon(tsize(ty, s->n_df, s->n_sue), s->n_type, s->n_df, s->n_sue); + ty = ty2; + rv = bcon(1); + df = s->n_df; + while (ISARY(ty)) { + rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) : + tempnode(-df->ddim, INT, 0, MKSUE(INT))); + df++; + ty = DECREF(ty); + } + rv = clocal(block(PMCONV, rv, r, INT, 0, MKSUE(INT))); + rv = optim(rv); + + r = block(PMCONV, q, rv, INT, 0, MKSUE(INT)); + r = clocal(r); + /* + * Indexing is only allowed with integer arguments, so insert + * SCONV here if arg is not an integer. + * XXX - complain? + */ + if (r->n_type != INT) + r = clocal(block(SCONV, r, NIL, INT, 0, MKSUE(INT))); + if (f == CVTL) + p->n_left = r; + else + p->n_right = r; + return(p); +} + +/* + * change enums to ints, or appropriate types + */ +void +econvert( p ) register NODE *p; { + + + register TWORD ty; + + if( (ty=BTYPE(p->n_type)) == ENUMTY || ty == MOETY ) { + if (p->n_sue->suesize == SZCHAR) + ty = INT; + else if (p->n_sue->suesize == SZINT) + ty = INT; + else if (p->n_sue->suesize == SZSHORT) + ty = INT; + else if (p->n_sue->suesize == SZLONGLONG) + ty = LONGLONG; + else + ty = LONG; + ty = ctype(ty); + p->n_sue = MKSUE(ty); + MODTYPE(p->n_type,ty); + if (p->n_op == ICON && ty != LONG && ty != LONGLONG) + p->n_type = INT, p->n_sue = MKSUE(INT); + } +} + +NODE * +pconvert( p ) register NODE *p; { + + /* if p should be changed into a pointer, do so */ + + if( ISARY( p->n_type) ){ + p->n_type = DECREF( p->n_type ); + ++p->n_df; + return( buildtree( ADDROF, p, NIL ) ); + } + if( ISFTN( p->n_type) ) + return( buildtree( ADDROF, p, NIL ) ); + + return( p ); + } + +NODE * +oconvert(p) register NODE *p; { + /* convert the result itself: used for pointer and unsigned */ + + switch(p->n_op) { + + case LE: + case LT: + case GE: + case GT: + if( ISUNSIGNED(p->n_left->n_type) || ISUNSIGNED(p->n_right->n_type) ) p->n_op += (ULE-LE); + case EQ: + case NE: + return( p ); + + case MINUS: + return( clocal( block( PVCONV, + p, bpsize(p->n_left), INT, 0, MKSUE(INT)))); + } + + cerror( "illegal oconvert: %d", p->n_op ); + + return(p); + } + +/* + * makes the operands of p agree; they are + * either pointers or integers, by this time + * with MINUS, the sizes must be the same + * with COLON, the types must be the same + */ +NODE * +ptmatch(NODE *p) +{ + struct suedef *sue, *sue2; + union dimfun *d, *d2; + TWORD t1, t2, t, q1, q2, q; + int o; + + o = p->n_op; + t = t1 = p->n_left->n_type; + q = q1 = p->n_left->n_qual; + t2 = p->n_right->n_type; + q2 = p->n_right->n_qual; + d = p->n_left->n_df; + d2 = p->n_right->n_df; + sue = p->n_left->n_sue; + sue2 = p->n_right->n_sue; + + switch( o ){ + + case ASSIGN: + case RETURN: + case CAST: + { break; } + + case MINUS: + { if( psize(p->n_left) != psize(p->n_right) ){ + uerror( "illegal pointer subtraction"); + } + break; + } + case COLON: + if (t1 != t2) { + /* + * Check for void pointer types. They are allowed + * to cast to/from any pointers. + */ + if (ISPTR(t1) && ISPTR(t2) && + (BTYPE(t1) == VOID || BTYPE(t2) == VOID)) + break; + uerror("illegal types in :"); + } + break; + + default: /* must work harder: relationals or comparisons */ + + if( !ISPTR(t1) ){ + t = t2; + q = q2; + d = d2; + sue = sue2; + break; + } + if( !ISPTR(t2) ){ + break; + } + + /* both are pointers */ + if( talign(t2,sue2) < talign(t,sue) ){ + t = t2; + q = q2; + sue = sue2; + } + break; + } + + p->n_left = makety( p->n_left, t, q, d, sue ); + p->n_right = makety( p->n_right, t, q, d, sue ); + if( o!=MINUS && !clogop(o) ){ + + p->n_type = t; + p->n_qual = q; + p->n_df = d; + p->n_sue = sue; + } + + return(clocal(p)); + } + +int tdebug = 0; + +NODE * +tymatch(p) register NODE *p; { + + /* satisfy the types of various arithmetic binary ops */ + + /* rules are: + if assignment, type of LHS + if any doubles, make double + else if any float make float + else if any longlongs, make long long + else if any longs, make long + else etcetc. + if either operand is unsigned, the result is... + */ + + TWORD t1, t2, t, tu; + int o, lu, ru; + + o = p->n_op; + + t1 = p->n_left->n_type; + t2 = p->n_right->n_type; + + lu = ru = 0; + if( ISUNSIGNED(t1) ){ + lu = 1; + t1 = DEUNSIGN(t1); + } + if( ISUNSIGNED(t2) ){ + ru = 1; + t2 = DEUNSIGN(t2); + } + + if (t1 == ENUMTY || t1 == MOETY) + t1 = INT; /* XXX */ + if (t2 == ENUMTY || t2 == MOETY) + t2 = INT; /* XXX */ +#if 0 + if ((t1 == CHAR || t1 == SHORT) && o!= RETURN) + t1 = INT; + if (t2 == CHAR || t2 == SHORT) + t2 = INT; +#endif + + if (t1 == LDOUBLE || t2 == LDOUBLE) + t = LDOUBLE; + else if (t1 == DOUBLE || t2 == DOUBLE) + t = DOUBLE; + else if (t1 == FLOAT || t2 == FLOAT) + t = FLOAT; + else if (t1==LONGLONG || t2 == LONGLONG) + t = LONGLONG; + else if (t1==LONG || t2==LONG) + t = LONG; + else /* if (t1==INT || t2==INT) */ + t = INT; +#if 0 + else if (t1==SHORT || t2==SHORT) + t = SHORT; + else + t = CHAR; +#endif + + if( casgop(o) ){ + tu = p->n_left->n_type; + t = t1; + } else { + tu = ((ru|lu) && UNSIGNABLE(t))?ENUNSIGN(t):t; + } + + /* because expressions have values that are at least as wide + as INT or UNSIGNED, the only conversions needed + are those involving FLOAT/DOUBLE, and those + from LONG to INT and ULONG to UNSIGNED */ + + + if (t != t1 || (ru && !lu)) + p->n_left = makety( p->n_left, tu, 0, 0, MKSUE(tu)); + + if (t != t2 || o==CAST || (lu && !ru)) + p->n_right = makety(p->n_right, tu, 0, 0, MKSUE(tu)); + + if( casgop(o) ){ + p->n_type = p->n_left->n_type; + p->n_df = p->n_left->n_df; + p->n_sue = p->n_left->n_sue; + } + else if( !clogop(o) ){ + p->n_type = tu; + p->n_df = NULL; + p->n_sue = MKSUE(t); + } + +#ifdef PCC_DEBUG + if (tdebug) { + printf("tymatch(%p): ", p); + tprint(stdout, t1, 0); + printf(" %s ", copst(o)); + tprint(stdout, t2, 0); + printf(" => "); + tprint(stdout, tu, 0); + printf("\n"); + } +#endif + + return(p); + } + +/* + * make p into type t by inserting a conversion + */ +NODE * +makety(NODE *p, TWORD t, TWORD q, union dimfun *d, struct suedef *sue) +{ + + if (p->n_type == ENUMTY && p->n_op == ICON) + econvert(p); + if (t == p->n_type) { + p->n_df = d; + p->n_sue = sue; + p->n_qual = q; + return(p); + } + + if ((p->n_type == FLOAT || p->n_type == DOUBLE || p->n_type == LDOUBLE) + && (t == FLOAT || t == DOUBLE || t == LDOUBLE) && p->n_op == FCON) { + p->n_type = t; + p->n_qual = q; + p->n_df = d; + p->n_sue = sue; + return(p); + } + + if (t & TMASK) { + /* non-simple type */ + p = block(PCONV, p, NIL, t, d, sue); + p->n_qual = q; + return clocal(p); + } + + if (p->n_op == ICON) { + if (t == DOUBLE || t == FLOAT) { + p->n_op = FCON; + if (ISUNSIGNED(p->n_type)) + p->n_dcon = (U_CONSZ) p->n_lval; + else + p->n_dcon = p->n_lval; + p->n_type = t; + p->n_qual = q; + p->n_sue = MKSUE(t); + return (clocal(p)); + } + } + p = block(SCONV, p, NIL, t, d, sue); + p->n_qual = q; + return clocal(p); + +} + +NODE * +block(int o, NODE *l, NODE *r, TWORD t, union dimfun *d, struct suedef *sue) +{ + register NODE *p; + + p = talloc(); + p->n_rval = 0; + p->n_op = o; + p->n_lval = 0; /* Protect against large lval */ + p->n_left = l; + p->n_right = r; + p->n_type = t; + p->n_qual = 0; + p->n_df = d; + p->n_sue = sue; +#if !defined(MULTIPASS) + /* p->n_reg = */p->n_su = 0; + p->n_regw = 0; +#endif + return(p); + } + +int +icons(p) register NODE *p; { + /* if p is an integer constant, return its value */ + int val; + + if( p->n_op != ICON ){ + uerror( "constant expected"); + val = 1; + } + else { + val = p->n_lval; + if( val != p->n_lval ) uerror( "constant too big for cross-compiler" ); + } + tfree( p ); + return(val); +} + +/* + * the intent of this table is to examine the + * operators, and to check them for + * correctness. + * + * The table is searched for the op and the + * modified type (where this is one of the + * types INT (includes char and short), LONG, + * DOUBLE (includes FLOAT), and POINTER + * + * The default action is to make the node type integer + * + * The actions taken include: + * PUN check for puns + * CVTL convert the left operand + * CVTR convert the right operand + * TYPL the type is determined by the left operand + * TYPR the type is determined by the right operand + * TYMATCH force type of left and right to match,by inserting conversions + * PTMATCH like TYMATCH, but for pointers + * LVAL left operand must be lval + * CVTO convert the op + * NCVT do not convert the operands + * OTHER handled by code + * NCVTR convert the left operand, not the right... + * + */ + +# define MINT 01 /* integer */ +# define MDBI 02 /* integer or double */ +# define MSTR 04 /* structure */ +# define MPTR 010 /* pointer */ +# define MPTI 020 /* pointer or integer */ +# define MENU 040 /* enumeration variable or member */ + +int +opact(NODE *p) +{ + int mt12, mt1, mt2, o; + + mt1 = mt2 = mt12 = 0; + + switch (coptype(o = p->n_op)) { + case BITYPE: + mt12=mt2 = moditype(p->n_right->n_type); + case UTYPE: + mt12 &= (mt1 = moditype(p->n_left->n_type)); + break; + } + + switch( o ){ + + case NAME : + case ICON : + case FCON : + case CALL : + case UCALL: + case UMUL: + { return( OTHER ); } + case UMINUS: + if( mt1 & MDBI ) return( TYPL ); + break; + + case COMPL: + if( mt1 & MINT ) return( TYPL ); + break; + + case ADDROF: + return( NCVT+OTHER ); + case NOT: +/* case INIT: */ + case CM: + case CBRANCH: + case ANDAND: + case OROR: + return( 0 ); + + case MUL: + case DIV: + if ((mt1&MDBI) && (mt2&MENU)) return( TYMATCH ); + if ((mt2&MDBI) && (mt1&MENU)) return( TYMATCH ); + if( mt12 & MDBI ) return( TYMATCH ); + break; + + case MOD: + case AND: + case OR: + case ER: + if( mt12 & MINT ) return( TYMATCH ); + break; + + case LS: + case RS: + if( mt12 & MINT ) return( TYPL+OTHER ); + break; + + case EQ: + case NE: + case LT: + case LE: + case GT: + case GE: + if( mt12 & MDBI ) return( TYMATCH+CVTO ); + else if( mt12 & MPTR ) return( PTMATCH+PUN ); + else if( mt12 & MPTI ) return( PTMATCH+PUN ); + else break; + + case QUEST: + case COMOP: + if( mt2&MENU ) return( TYPR+NCVTR ); + return( TYPR ); + + case STREF: + return( NCVTR+OTHER ); + + case FORCE: + return( TYPL ); + + case COLON: + if( mt12 & MDBI ) return( TYMATCH ); + else if( mt12 & MPTR ) return( TYPL+PTMATCH+PUN ); + else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+PUN ); + else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+PUN ); + else if( mt12 & MSTR ) return( NCVT+TYPL+OTHER ); + break; + + case ASSIGN: + case RETURN: + if( mt12 & MSTR ) return( LVAL+NCVT+TYPL+OTHER ); + case CAST: + if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH ); +#if 0 + else if(mt1&MENU && mt2&MDBI) return( TYPL+LVAL+TYMATCH ); + else if(mt2&MENU && mt1&MDBI) return( TYPL+LVAL+TYMATCH ); + else if( (mt1&MENU)||(mt2&MENU) ) + return( LVAL+NCVT+TYPL+PTMATCH+PUN ); +#endif + else if( mt1 & MPTR) return( LVAL+PTMATCH+PUN ); + else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN ); + break; + + case LSEQ: + case RSEQ: + if( mt12 & MINT ) return( TYPL+LVAL+OTHER ); + break; + + case MULEQ: + case DIVEQ: + if( mt12 & MDBI ) return( LVAL+TYMATCH ); + break; + + case MODEQ: + case ANDEQ: + case OREQ: + case EREQ: + if (mt12 & MINT) + return(LVAL+TYMATCH); + break; + + case PLUSEQ: + case MINUSEQ: + case INCR: + case DECR: + if (mt12 & MDBI) + return(TYMATCH+LVAL); + else if ((mt1&MPTR) && (mt2&MINT)) + return(TYPL+LVAL+CVTR); + break; + + case MINUS: + if (mt12 & MPTR) + return(CVTO+PTMATCH+PUN); + if (mt2 & MPTR) + break; + /* FALLTHROUGH */ + case PLUS: + if (mt12 & MDBI) + return(TYMATCH); + else if ((mt1&MPTR) && (mt2&MINT)) + return(TYPL+CVTR); + else if ((mt1&MINT) && (mt2&MPTR)) + return(TYPR+CVTL); + + } + uerror("operands of %s have incompatible types", copst(o)); + return(NCVT); +} + +int +moditype(TWORD ty) +{ + switch (ty) { + + case ENUMTY: + case MOETY: + return( MENU|MINT|MDBI|MPTI ); + + case STRTY: + case UNIONTY: + return( MSTR ); + + case BOOL: + case CHAR: + case SHORT: + case UCHAR: + case USHORT: + case UNSIGNED: + case ULONG: + case ULONGLONG: + case INT: + case LONG: + case LONGLONG: + return( MINT|MDBI|MPTI ); + case FLOAT: + case DOUBLE: + case LDOUBLE: + return( MDBI ); + default: + return( MPTR|MPTI ); + + } +} + +int tvaloff = 100; + +/* + * Returns a TEMP node with temp number nr. + * If nr == 0, return a node with a new number. + */ +NODE * +tempnode(int nr, TWORD type, union dimfun *df, struct suedef *sue) +{ + NODE *r; + + r = block(TEMP, NIL, NIL, type, df, sue); + r->n_lval = nr ? nr : tvaloff; + tvaloff += szty(type); + return r; +} + +/* + * Do sizeof on p. + */ +NODE * +doszof(NODE *p) +{ + union dimfun *df; + TWORD ty; + NODE *rv; + + if (p->n_op == FLD) + uerror("can't apply sizeof to bit-field"); + + /* + * Arrays may be dynamic, may need to make computations. + */ + + rv = bcon(1); + df = p->n_df; + ty = p->n_type; + while (ISARY(ty)) { + rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) : + tempnode(-df->ddim, INT, 0, MKSUE(INT))); + df++; + ty = DECREF(ty); + } + rv = buildtree(MUL, rv, bcon(tsize(ty, p->n_df, p->n_sue)/SZCHAR)); + tfree(p); + return rv; +} + +#ifdef PCC_DEBUG +void +eprint(NODE *p, int down, int *a, int *b) +{ + int ty; + + *a = *b = down+1; + while( down > 1 ){ + printf( "\t" ); + down -= 2; + } + if( down ) printf( " " ); + + ty = coptype( p->n_op ); + + printf("%p) %s, ", p, copst(p->n_op)); + if (ty == LTYPE) { + printf(CONFMT, p->n_lval); + printf(", %d, ", p->n_rval); + } + tprint(stdout, p->n_type, p->n_qual); + printf( ", %p, %p\n", p->n_df, p->n_sue ); +} +# endif + +void +prtdcon(NODE *p) +{ + int o = p->n_op, i; + + if (o != FCON) + return; + + /* Write float constants to memory */ + /* Should be volontary per architecture */ + + setloc1(RDATA); + defalign(p->n_type == FLOAT ? ALFLOAT : p->n_type == DOUBLE ? + ALDOUBLE : ALLDOUBLE ); + deflab1(i = getlab()); + ninval(0, btdims[p->n_type].suesize, p); + p->n_op = NAME; + p->n_lval = 0; + p->n_sp = tmpalloc(sizeof(struct symtab_hdr)); + p->n_sp->sclass = ILABEL; + p->n_sp->soffset = i; +} + +extern int negrel[]; + +/* + * Walk up through the tree from the leaves, + * removing constant operators. + */ +static void +logwalk(NODE *p) +{ + int o = coptype(p->n_op); + NODE *l, *r; + + l = p->n_left; + r = p->n_right; + switch (o) { + case LTYPE: + return; + case BITYPE: + logwalk(r); + case UTYPE: + logwalk(l); + } + if (!clogop(p->n_op)) + return; + if (p->n_op == NOT && l->n_op == ICON) { + p->n_lval = l->n_lval == 0; + nfree(l); + p->n_op = ICON; + } + if (l->n_op == ICON && r->n_op == ICON) { + if (conval(l, p->n_op, r) == 0) { + /* + * people sometimes tend to do really odd compares, + * like "if ("abc" == "def")" etc. + * do it runtime instead. + */ + } else { + p->n_lval = l->n_lval; + p->n_op = ICON; + nfree(l); + nfree(r); + } + } +} + +/* + * Removes redundant logical operators for branch conditions. + */ +static void +fixbranch(NODE *p, int label) +{ + + logwalk(p); + + if (p->n_op == ICON) { + if (p->n_lval != 0) + branch(label); + nfree(p); + } else { + if (!clogop(p->n_op)) /* Always conditional */ + p = buildtree(NE, p, bcon(0)); + ecode(buildtree(CBRANCH, p, bcon(label))); + } +} + +/* + * Write out logical expressions as branches. + */ +static void +andorbr(NODE *p, int true, int false) +{ + NODE *q; + int o, lab; + + lab = -1; + switch (o = p->n_op) { + case EQ: + case NE: + /* + * Remove redundant EQ/NE nodes. + */ + while (((o = p->n_left->n_op) == EQ || o == NE) && + p->n_right->n_op == ICON) { + o = p->n_op; + q = p->n_left; + if (p->n_right->n_lval == 0) { + nfree(p->n_right); + *p = *q; + nfree(q); + if (o == EQ) + p->n_op = negrel[p->n_op - EQ]; +// p->n_op = NE; /* toggla */ + } else if (p->n_right->n_lval == 1) { + nfree(p->n_right); + *p = *q; + nfree(q); + if (o == NE) + p->n_op = negrel[p->n_op - EQ]; +// p->n_op = EQ; /* toggla */ + } else + break; /* XXX - should always be false */ + + } + /* FALLTHROUGH */ + case LE: + case LT: + case GE: + case GT: +calc: if (true < 0) { + p->n_op = negrel[p->n_op - EQ]; + true = false; + false = -1; + } + + rmcops(p->n_left); + rmcops(p->n_right); + fixbranch(p, true); + if (false >= 0) + branch(false); + break; + + case ULE: + case UGT: + /* Convert to friendlier ops */ + if (p->n_right->n_op == ICON && p->n_right->n_lval == 0) + p->n_op = o == ULE ? EQ : NE; + goto calc; + + case UGE: + case ULT: + /* Already true/false by definition */ + if (p->n_right->n_op == ICON && p->n_right->n_lval == 0) { + if (true < 0) { + o = o == ULT ? UGE : ULT; + true = false; + } + rmcops(p->n_left); + ecode(p->n_left); + rmcops(p->n_right); + ecode(p->n_right); + nfree(p); + if (o == UGE) /* true */ + branch(true); + break; + } + goto calc; + + case ANDAND: + lab = false<0 ? getlab() : false ; + andorbr(p->n_left, -1, lab); + andorbr(p->n_right, true, false); + if (false < 0) + plabel( lab); + nfree(p); + break; + + case OROR: + lab = true<0 ? getlab() : true; + andorbr(p->n_left, lab, -1); + andorbr(p->n_right, true, false); + if (true < 0) + plabel( lab); + nfree(p); + break; + + case NOT: + andorbr(p->n_left, false, true); + nfree(p); + break; + + default: + rmcops(p); + if (true >= 0) + fixbranch(p, true); + if (false >= 0) { + if (true >= 0) + branch(false); + else + fixbranch(buildtree(EQ, p, bcon(0)), false); + } + } +} + +/* + * Massage the output trees to remove C-specific nodes: + * COMOPs are split into separate statements. + * QUEST/COLON are rewritten to branches. + * ANDAND/OROR/NOT are rewritten to branches for lazy-evaluation. + * CBRANCH conditions are rewritten for lazy-evaluation. + */ +static void +rmcops(NODE *p) +{ + TWORD type; + NODE *q, *r; + int o, ty, lbl, lbl2, tval = 0; + +again: + o = p->n_op; + ty = coptype(o); + switch (o) { + case QUEST: + + /* + * Create a branch node from ?: + * || and && must be taken special care of. + */ + type = p->n_type; + andorbr(p->n_left, -1, lbl = getlab()); + + /* Make ASSIGN node */ + /* Only if type is not void */ + q = p->n_right->n_left; + if (type != VOID) { + r = tempnode(0, q->n_type, q->n_df, q->n_sue); + tval = r->n_lval; + q = buildtree(ASSIGN, r, q); + } + rmcops(q); + ecode(q); /* Done with assign */ + branch(lbl2 = getlab()); + plabel( lbl); + + q = p->n_right->n_right; + if (type != VOID) { + r = tempnode(tval, q->n_type, q->n_df, q->n_sue); + q = buildtree(ASSIGN, r, q); + } + rmcops(q); + ecode(q); /* Done with assign */ + + plabel( lbl2); + + nfree(p->n_right); + if (p->n_type != VOID) { + r = tempnode(tval, p->n_type, p->n_df, p->n_sue); + *p = *r; + nfree(r); + } else + p->n_op = ICON; + break; + + case ULE: + case ULT: + case UGE: + case UGT: + case EQ: + case NE: + case LE: + case LT: + case GE: + case GT: + case ANDAND: + case OROR: + case NOT: +#ifdef SPECIAL_CCODES +#error fix for private CCODES handling +#else + r = talloc(); + *r = *p; + andorbr(r, -1, lbl = getlab()); + q = tempnode(0, p->n_type, p->n_df, p->n_sue); + tval = q->n_lval; + r = tempnode(tval, p->n_type, p->n_df, p->n_sue); + ecode(buildtree(ASSIGN, q, bcon(1))); + branch(lbl2 = getlab()); + plabel( lbl); + ecode(buildtree(ASSIGN, r, bcon(0))); + plabel( lbl2); + r = tempnode(tval, p->n_type, p->n_df, p->n_sue); + *p = *r; + nfree(r); +#endif + break; + case CBRANCH: + andorbr(p->n_left, p->n_right->n_lval, -1); + nfree(p->n_right); + p->n_op = ICON; p->n_type = VOID; + break; + case COMOP: + rmcops(p->n_left); + ecode(p->n_left); + /* Now when left tree is dealt with, rm COMOP */ + q = p->n_right; + *p = *p->n_right; + nfree(q); + goto again; + + default: + if (ty == LTYPE) + return; + rmcops(p->n_left); + if (ty == BITYPE) + rmcops(p->n_right); + } +} + +/* + * Return 1 if an assignment is found. + */ +static int +has_se(NODE *p) +{ + if (cdope(p->n_op) & ASGFLG) + return 1; + if (coptype(p->n_op) == LTYPE) + return 0; + if (has_se(p->n_left)) + return 1; + if (coptype(p->n_op) == BITYPE) + return has_se(p->n_right); + return 0; +} + +/* + * Find and convert asgop's to separate statements. + * Be careful about side effects. + * assign tells whether ASSIGN should be considered giving + * side effects or not. + */ +static NODE * +delasgop(NODE *p) +{ + NODE *q, *r; + int tval; + + if (p->n_op == INCR || p->n_op == DECR) { + /* + * Rewrite x++ to (x += 1) -1; and deal with it further down. + * Pass2 will remove -1 if unneccessary. + */ + q = ccopy(p); + tfree(p->n_left); + q->n_op = (p->n_op==INCR)?PLUSEQ:MINUSEQ; + p->n_op = (p->n_op==INCR)?MINUS:PLUS; + p->n_left = delasgop(q); + + } else if ((cdope(p->n_op)&ASGOPFLG) && + p->n_op != RETURN && p->n_op != CAST) { + NODE *l = p->n_left; + NODE *ll = l->n_left; + + if (has_se(l)) { + q = tempnode(0, ll->n_type, ll->n_df, ll->n_sue); + tval = q->n_lval; + r = tempnode(tval, ll->n_type, ll->n_df,ll->n_sue); + l->n_left = q; + /* Now the left side of node p has no side effects. */ + /* side effects on the right side must be obeyed */ + p = delasgop(p); + + r = buildtree(ASSIGN, r, ll); + r = delasgop(r); + ecode(r); + } else { +#if 0 /* Cannot call buildtree() here, it would invoke double add shifts */ + p->n_right = buildtree(UNASG p->n_op, ccopy(l), + p->n_right); +#else + p->n_right = block(UNASG p->n_op, ccopy(l), + p->n_right, p->n_type, p->n_df, p->n_sue); +#endif + p->n_op = ASSIGN; + p->n_right = delasgop(p->n_right); + p->n_right = clocal(p->n_right); + } + + } else { + if (coptype(p->n_op) == LTYPE) + return p; + p->n_left = delasgop(p->n_left); + if (coptype(p->n_op) == BITYPE) + p->n_right = delasgop(p->n_right); + } + return p; +} + +int edebug = 0; +void +ecomp(NODE *p) +{ + +#ifdef PCC_DEBUG + if (edebug) + fwalk(p, eprint, 0); +#endif + if (!reached) { + werror("statement not reached"); + reached = 1; + } + p = optim(p); + rmcops(p); + p = delasgop(p); + setloc1(PROG); + if (p->n_op == ICON && p->n_type == VOID) + tfree(p); + else + ecode(p); +} + +#if defined(MULTIPASS) +void +p2tree(NODE *p) +{ + struct symtab *q; + int ty; + +# ifdef MYP2TREE + MYP2TREE(p); /* local action can be taken here; then return... */ +# endif + + ty = coptype(p->n_op); + + printf("%d\t", p->n_op); + + if (ty == LTYPE) { + printf(CONFMT, p->n_lval); + printf("\t"); + } + if (ty != BITYPE) { + if (p->n_op == NAME || p->n_op == ICON) + printf("0\t"); + else + printf("%d\t", p->n_rval); + } + + printf("%o\t", p->n_type); + + /* handle special cases */ + + switch (p->n_op) { + + case NAME: + case ICON: + /* print external name */ + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0) || + q->sclass == ILABEL) { + printf(LABFMT, q->soffset); + } else + printf("%s\n", exname(q->sname)); + } else + printf("\n"); + break; + + case STARG: + case STASG: + case STCALL: + case USTCALL: + /* print out size */ + /* use lhs size, in order to avoid hassles + * with the structure `.' operator + */ + + /* note: p->left not a field... */ + printf(CONFMT, (CONSZ)tsize(STRTY, p->n_left->n_df, + p->n_left->n_sue)); + printf("\t%d\t\n", talign(STRTY, p->n_left->n_sue)); + break; + + default: + printf( "\n" ); + } + + if (ty != LTYPE) + p2tree(p->n_left); + if (ty == BITYPE) + p2tree(p->n_right); +} +#else +void +p2tree(NODE *p) +{ + struct symtab *q; + int ty; + +# ifdef MYP2TREE + MYP2TREE(p); /* local action can be taken here; then return... */ +# endif + + ty = coptype(p->n_op); + + switch( p->n_op ){ + + case NAME: + case ICON: + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0) || +#ifdef GCC_COMPAT + q->sflags == SLBLNAME || +#endif + q->sclass == ILABEL) { + char *cp = (isinlining ? + permalloc(32) : tmpalloc(32)); + int n = q->soffset; + if (n < 0) + n = -n; + snprintf(cp, 32, LABFMT, n); + p->n_name = cp; + } else { +#ifdef GCC_COMPAT + p->n_name = gcc_findname(q); +#else + p->n_name = exname(q->sname); +#endif + } + } else + p->n_name = ""; + break; + + case STASG: + /* STASG used for stack array init */ + if (ISARY(p->n_type)) { + int size1 = tsize(p->n_type, p->n_left->n_df, + p->n_left->n_sue)/SZCHAR; + p->n_stsize = tsize(p->n_type, p->n_right->n_df, + p->n_right->n_sue)/SZCHAR; + if (size1 < p->n_stsize) + p->n_stsize = size1; + p->n_stalign = talign(p->n_type, + p->n_left->n_sue)/SZCHAR; + break; + } + /* FALLTHROUGH */ + case STARG: + case STCALL: + case USTCALL: + /* set up size parameters */ + p->n_stsize = (tsize(STRTY, p->n_left->n_df, + p->n_left->n_sue)+SZCHAR-1)/SZCHAR; + p->n_stalign = talign(STRTY,p->n_left->n_sue)/SZCHAR; + break; + + default: + p->n_name = ""; + } + + if( ty != LTYPE ) p2tree( p->n_left ); + if( ty == BITYPE ) p2tree( p->n_right ); + } + +#endif + +/* + * Change void data types into char. + */ +static void +delvoid(NODE *p) +{ + /* Convert "PTR undef" (void *) to "PTR uchar" */ + if (BTYPE(p->n_type) == VOID) + p->n_type = (p->n_type & ~BTMASK) | UCHAR; + if (BTYPE(p->n_type) == BOOL) { + if (p->n_op == SCONV && p->n_type == BOOL) { + /* create a jump and a set */ + NODE *q, *r, *s; + int l, val; + + q = talloc(); + *q = *p; + q->n_type = BOOL_TYPE; + r = tempnode(0, BOOL_TYPE, NULL, MKSUE(BOOL_TYPE)); + val = r->n_lval; + s = tempnode(val, BOOL_TYPE, NULL, MKSUE(BOOL_TYPE)); + *p = *s; + q = buildtree(ASSIGN, r, q); + cbranch(buildtree(EQ, q, bcon(0)), bcon(l = getlab())); + ecode(buildtree(ASSIGN, s, bcon(1))); + plabel(l); + } else + p->n_type = (p->n_type & ~BTMASK) | BOOL_TYPE; + } + +} + +void +ecode(NODE *p) +{ + /* walk the tree and write out the nodes.. */ + + if (nerrors) + return; + + p = optim(p); + p = delasgop(p); + walkf(p, prtdcon); + walkf(p, delvoid); +#ifdef PCC_DEBUG + if (xdebug) { + printf("Fulltree:\n"); + fwalk(p, eprint, 0); + } +#endif + p2tree(p); +#if !defined(MULTIPASS) + send_passt(IP_NODE, p); +#endif +} + +/* + * Send something further on to the next pass. + */ +void +send_passt(int type, ...) +{ + struct interpass *ip; + struct interpass_prolog *ipp; + extern int crslab; + va_list ap; + int sz; + + va_start(ap, type); + if (type == IP_PROLOG || type == IP_EPILOG) + sz = sizeof(struct interpass_prolog); + else + sz = sizeof(struct interpass); + + ip = isinlining ? permalloc(sz) : tmpalloc(sz); + ip->type = type; + ip->lineno = lineno; + switch (type) { + case IP_NODE: + if (lastloc != PROG) + setloc1(PROG); + ip->ip_node = va_arg(ap, NODE *); + break; + case IP_EPILOG: + case IP_PROLOG: + setloc1(PROG); + ipp = (struct interpass_prolog *)ip; + ipp->ipp_regs = va_arg(ap, int); + ipp->ipp_autos = va_arg(ap, int); + ipp->ipp_name = va_arg(ap, char *); + ipp->ipp_type = va_arg(ap, TWORD); + ipp->ipp_vis = va_arg(ap, int); + ip->ip_lbl = va_arg(ap, int); + ipp->ip_tmpnum = tvaloff; + ipp->ip_lblnum = crslab; + if (type == IP_PROLOG) + ipp->ip_lblnum--; + break; + case IP_DEFLAB: + ip->ip_lbl = va_arg(ap, int); + break; + case IP_ASM: + if (blevel == 0) { /* outside function */ + printf("\t%s\n", va_arg(ap, char *)); + va_end(ap); + lastloc = -1; + return; + } + ip->ip_asm = va_arg(ap, char *); + break; + default: + cerror("bad send_passt type %d", type); + } + va_end(ap); + if (isinlining) + inline_addarg(ip); + else + pass2_compile(ip); + if (type == IP_EPILOG) + lastloc = PROG; +} + +char * +copst(int op) +{ + if (op <= MAXOP) + return opst[op]; +#define SNAM(x,y) case x: return #y; + switch (op) { + SNAM(QUALIFIER,QUALIFIER) + SNAM(CLASS,CLASS) + SNAM(RB,]) + SNAM(DOT,.) + SNAM(ELLIPSIS,...) + SNAM(LB,[) + SNAM(TYPE,TYPE) + SNAM(COMOP,COMOP) + SNAM(QUEST,?) + SNAM(COLON,:) + SNAM(ANDAND,&&) + SNAM(OROR,||) + SNAM(NOT,!) + SNAM(CAST,CAST) + SNAM(PLUSEQ,+=) + SNAM(MINUSEQ,-=) + SNAM(MULEQ,*=) + SNAM(DIVEQ,/=) + SNAM(MODEQ,%=) + SNAM(ANDEQ,&=) + SNAM(OREQ,|=) + SNAM(EREQ,^=) + SNAM(LSEQ,<<=) + SNAM(RSEQ,>>=) + SNAM(INCR,++) + SNAM(DECR,--) + default: + cerror("bad copst %d", op); + } + return 0; /* XXX gcc */ +} + +int +cdope(int op) +{ + if (op <= MAXOP) + return dope[op]; + switch (op) { + case QUALIFIER: + case CLASS: + case RB: + case DOT: + case ELLIPSIS: + case TYPE: + return LTYPE; + case COMOP: + case QUEST: + case COLON: + case LB: + return BITYPE; + case ANDAND: + case OROR: + return BITYPE|LOGFLG; + case NOT: + return UTYPE|LOGFLG; + case CAST: + return BITYPE|ASGFLG|ASGOPFLG; + case PLUSEQ: + return BITYPE|ASGFLG|ASGOPFLG|FLOFLG|SIMPFLG|COMMFLG; + case MINUSEQ: + return BITYPE|FLOFLG|SIMPFLG|ASGFLG|ASGOPFLG; + case MULEQ: + return BITYPE|FLOFLG|MULFLG|ASGFLG|ASGOPFLG; + case OREQ: + case EREQ: + case ANDEQ: + return BITYPE|SIMPFLG|COMMFLG|ASGFLG|ASGOPFLG; + case DIVEQ: + return BITYPE|FLOFLG|MULFLG|DIVFLG|ASGFLG|ASGOPFLG; + case MODEQ: + return BITYPE|DIVFLG|ASGFLG|ASGOPFLG; + case LSEQ: + case RSEQ: + return BITYPE|SHFFLG|ASGFLG|ASGOPFLG; + case INCR: + case DECR: + return BITYPE|ASGFLG; + } + return 0; /* XXX gcc */ +} + +/* + * make a fresh copy of p + */ +NODE * +ccopy(NODE *p) +{ + NODE *q; + + q = talloc(); + *q = *p; + + switch (coptype(q->n_op)) { + case BITYPE: + q->n_right = ccopy(p->n_right); + case UTYPE: + q->n_left = ccopy(p->n_left); + } + + return(q); +} + +/* + * set PROG-seg label. + */ +void +plabel(int label) +{ + setloc1(PROG); + reached = 1; /* Will this always be correct? */ + send_passt(IP_DEFLAB, label); +} diff --git a/usr.bin/pcc/ccom/vax/Makefile b/usr.bin/pcc/ccom/vax/Makefile new file mode 100644 index 00000000000..5b10f3f479d --- /dev/null +++ b/usr.bin/pcc/ccom/vax/Makefile @@ -0,0 +1,3 @@ +TARGMACH= vax + +.include <bsd.prog.mk> diff --git a/usr.bin/pcc/ccom/x86/Makefile b/usr.bin/pcc/ccom/x86/Makefile new file mode 100644 index 00000000000..2049d325ec4 --- /dev/null +++ b/usr.bin/pcc/ccom/x86/Makefile @@ -0,0 +1,3 @@ +TARGMACH= x86 + +.include <bsd.prog.mk> |