summaryrefslogtreecommitdiff
path: root/usr.bin/pcc/ccom
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2007-10-07 17:58:53 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2007-10-07 17:58:53 +0000
commit14b353bdf99a61b29314822d06fff3f7250019ac (patch)
treecfb9b82ab66c64756933986a1d66b0b133819ab4 /usr.bin/pcc/ccom
parent71267fa7f73e6e874cf9cb489551cb44ead37aba (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/Makefile9
-rw-r--r--usr.bin/pcc/ccom/Makefile.inc45
-rw-r--r--usr.bin/pcc/ccom/ccom.1167
-rw-r--r--usr.bin/pcc/ccom/cgram.y1403
-rw-r--r--usr.bin/pcc/ccom/gcc_compat.c126
-rw-r--r--usr.bin/pcc/ccom/init.c968
-rw-r--r--usr.bin/pcc/ccom/inline.c209
-rw-r--r--usr.bin/pcc/ccom/main.c317
-rw-r--r--usr.bin/pcc/ccom/optim.c355
-rw-r--r--usr.bin/pcc/ccom/pass1.h394
-rw-r--r--usr.bin/pcc/ccom/pftn.c2676
-rw-r--r--usr.bin/pcc/ccom/scan.l467
-rw-r--r--usr.bin/pcc/ccom/stabs.c374
-rw-r--r--usr.bin/pcc/ccom/symtabs.c356
-rw-r--r--usr.bin/pcc/ccom/trees.c2466
-rw-r--r--usr.bin/pcc/ccom/vax/Makefile3
-rw-r--r--usr.bin/pcc/ccom/x86/Makefile3
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>