summaryrefslogtreecommitdiffstats
path: root/usr.bin/xlint/lint1
diff options
context:
space:
mode:
authorjoerg <joerg@FreeBSD.org>1995-11-05 15:56:42 +0000
committerjoerg <joerg@FreeBSD.org>1995-11-05 15:56:42 +0000
commit97ea65b2cb83e7b5b2c4afcacc3a185482457c2a (patch)
treee48ecf34ec80fd6977218c2852e4419794cc64d7 /usr.bin/xlint/lint1
downloadFreeBSD-src-97ea65b2cb83e7b5b2c4afcacc3a185482457c2a.zip
FreeBSD-src-97ea65b2cb83e7b5b2c4afcacc3a185482457c2a.tar.gz
Jochen Pohl's lint(1) from NetBSD. Yet another import.
This is just a vendor import by now. I'll wait until i'll get the imported files back via CTM before applying the FreeBSD patches. Don't use it yet. Submitted by: Jochen Pohl <jpo.drs@sni.de> Obtained from: (NetBSD -- this version is directly from Jochen)
Diffstat (limited to 'usr.bin/xlint/lint1')
-rw-r--r--usr.bin/xlint/lint1/Makefile19
-rw-r--r--usr.bin/xlint/lint1/cgram.y1675
-rw-r--r--usr.bin/xlint/lint1/decl.c3134
-rw-r--r--usr.bin/xlint/lint1/emit.c241
-rw-r--r--usr.bin/xlint/lint1/emit1.c587
-rw-r--r--usr.bin/xlint/lint1/err.c543
-rw-r--r--usr.bin/xlint/lint1/externs.h56
-rw-r--r--usr.bin/xlint/lint1/externs1.h281
-rw-r--r--usr.bin/xlint/lint1/func.c1261
-rw-r--r--usr.bin/xlint/lint1/init.c513
-rw-r--r--usr.bin/xlint/lint1/lint.h118
-rw-r--r--usr.bin/xlint/lint1/lint1.h380
-rw-r--r--usr.bin/xlint/lint1/main1.c183
-rw-r--r--usr.bin/xlint/lint1/mem.c91
-rw-r--r--usr.bin/xlint/lint1/mem1.c358
-rw-r--r--usr.bin/xlint/lint1/op.h120
-rw-r--r--usr.bin/xlint/lint1/param.h120
-rw-r--r--usr.bin/xlint/lint1/scan.l1426
-rw-r--r--usr.bin/xlint/lint1/tree.c3924
19 files changed, 15030 insertions, 0 deletions
diff --git a/usr.bin/xlint/lint1/Makefile b/usr.bin/xlint/lint1/Makefile
new file mode 100644
index 0000000..d5e519a
--- /dev/null
+++ b/usr.bin/xlint/lint1/Makefile
@@ -0,0 +1,19 @@
+# $NetBSD: Makefile,v 1.3 1995/07/04 01:53:05 cgd Exp $
+
+PROG= lint1
+SRCS= cgram.c scan.c mem1.c mem.c err.c main1.c decl.c tree.c func.c \
+ init.c emit.c emit1.c
+NOMAN=
+LDADD+= -ll
+DPADD+= ${LIBL}
+YFLAGS= -d
+CFLAGS+=-I.
+LINTFLAGS=-aehpz
+CLEANFILES+=y.tab.h cgram.c scan.c
+
+BINDIR= /usr/libexec
+
+# XXX: -O causes the gcc to die on the i386, when compiling tree.o
+CFLAGS+= -DXXX_BROKEN_GCC
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/xlint/lint1/cgram.y b/usr.bin/xlint/lint1/cgram.y
new file mode 100644
index 0000000..e65584a
--- /dev/null
+++ b/usr.bin/xlint/lint1/cgram.y
@@ -0,0 +1,1675 @@
+%{
+/* $NetBSD: cgram.y,v 1.8 1995/10/02 17:31:35 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: cgram.y,v 1.8 1995/10/02 17:31:35 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+#include <limits.h>
+
+#include "lint1.h"
+
+/*
+ * Contains the level of current declaration. 0 is extern.
+ * Used for symbol table entries.
+ */
+int blklev;
+
+/*
+ * level for memory allocation. Normaly the same as blklev.
+ * An exeption is the declaration of arguments in prototypes. Memory
+ * for these can't be freed after the declaration, but symbols must
+ * be removed from the symbol table after the declaration.
+ */
+int mblklev;
+
+static int toicon __P((tnode_t *));
+static void idecl __P((sym_t *, int));
+static void ignuptorp __P((void));
+
+%}
+
+%union {
+ int y_int;
+ val_t *y_val;
+ sbuf_t *y_sb;
+ sym_t *y_sym;
+ op_t y_op;
+ scl_t y_scl;
+ tspec_t y_tspec;
+ tqual_t y_tqual;
+ type_t *y_type;
+ tnode_t *y_tnode;
+ strg_t *y_strg;
+ pqinf_t *y_pqinf;
+};
+
+%token T_LBRACE T_RBRACE T_LBRACK T_RBRACK T_LPARN T_RPARN
+%token <y_op> T_STROP
+%token <y_op> T_UNOP
+%token <y_op> T_INCDEC
+%token T_SIZEOF
+%token <y_op> T_MULT
+%token <y_op> T_DIVOP
+%token <y_op> T_ADDOP
+%token <y_op> T_SHFTOP
+%token <y_op> T_RELOP
+%token <y_op> T_EQOP
+%token <y_op> T_AND
+%token <y_op> T_XOR
+%token <y_op> T_OR
+%token <y_op> T_LOGAND
+%token <y_op> T_LOGOR
+%token T_QUEST
+%token T_COLON
+%token <y_op> T_ASSIGN
+%token <y_op> T_OPASS
+%token T_COMMA
+%token T_SEMI
+%token T_ELLIPSE
+
+/* storage classes (extern, static, auto, register and typedef) */
+%token <y_scl> T_SCLASS
+
+/* types (char, int, short, long, unsigned, signed, float, double, void) */
+%token <y_tspec> T_TYPE
+
+/* qualifiers (const, volatile) */
+%token <y_tqual> T_QUAL
+
+/* struct or union */
+%token <y_tspec> T_SOU
+
+/* enum */
+%token T_ENUM
+
+/* remaining keywords */
+%token T_CASE
+%token T_DEFAULT
+%token T_IF
+%token T_ELSE
+%token T_SWITCH
+%token T_DO
+%token T_WHILE
+%token T_FOR
+%token T_GOTO
+%token T_CONTINUE
+%token T_BREAK
+%token T_RETURN
+%token T_ASM
+
+%left T_COMMA
+%right T_ASSIGN T_OPASS
+%right T_QUEST T_COLON
+%left T_LOGOR
+%left T_LOGAND
+%left T_OR
+%left T_XOR
+%left T_AND
+%left T_EQOP
+%left T_RELOP
+%left T_SHFTOP
+%left T_ADDOP
+%left T_MULT T_DIVOP
+%right T_UNOP T_INCDEC T_SIZEOF
+%left T_LPARN T_LBRACK T_STROP
+
+%token <y_sb> T_NAME
+%token <y_sb> T_TYPENAME
+%token <y_val> T_CON
+%token <y_strg> T_STRING
+
+%type <y_sym> func_decl
+%type <y_sym> notype_decl
+%type <y_sym> type_decl
+%type <y_type> typespec
+%type <y_type> clrtyp_typespec
+%type <y_type> notype_typespec
+%type <y_type> struct_spec
+%type <y_type> enum_spec
+%type <y_sym> struct_tag
+%type <y_sym> enum_tag
+%type <y_tspec> struct
+%type <y_sym> struct_declaration
+%type <y_sb> identifier
+%type <y_sym> member_declaration_list_with_rbrace
+%type <y_sym> member_declaration_list
+%type <y_sym> member_declaration
+%type <y_sym> notype_member_decls
+%type <y_sym> type_member_decls
+%type <y_sym> notype_member_decl
+%type <y_sym> type_member_decl
+%type <y_tnode> constant
+%type <y_sym> enum_declaration
+%type <y_sym> enums_with_opt_comma
+%type <y_sym> enums
+%type <y_sym> enumerator
+%type <y_sym> ename
+%type <y_sym> notype_direct_decl
+%type <y_sym> type_direct_decl
+%type <y_pqinf> pointer
+%type <y_pqinf> asterisk
+%type <y_sym> param_decl
+%type <y_sym> param_list
+%type <y_sym> abs_decl_param_list
+%type <y_sym> direct_param_decl
+%type <y_sym> notype_param_decl
+%type <y_sym> direct_notype_param_decl
+%type <y_pqinf> type_qualifier_list
+%type <y_pqinf> type_qualifier
+%type <y_sym> identifier_list
+%type <y_sym> abs_decl
+%type <y_sym> direct_abs_decl
+%type <y_sym> vararg_parameter_type_list
+%type <y_sym> parameter_type_list
+%type <y_sym> parameter_declaration
+%type <y_tnode> expr
+%type <y_tnode> term
+%type <y_tnode> func_arg_list
+%type <y_op> point_or_arrow
+%type <y_type> type_name
+%type <y_sym> abstract_declaration
+%type <y_tnode> do_while_expr
+%type <y_tnode> opt_expr
+%type <y_strg> string
+%type <y_strg> string2
+
+
+%%
+
+program:
+ /* empty */ {
+ if (sflag) {
+ /* empty translation unit */
+ error(272);
+ } else if (!tflag) {
+ /* empty translation unit */
+ warning(272);
+ }
+ }
+ | translation_unit
+ ;
+
+translation_unit:
+ ext_decl
+ | translation_unit ext_decl
+ ;
+
+ext_decl:
+ func_def {
+ glclup(0);
+ clrwflgs();
+ }
+ | data_def {
+ glclup(0);
+ clrwflgs();
+ }
+ ;
+
+data_def:
+ T_SEMI {
+ if (sflag) {
+ /* syntax error: empty declaration */
+ error(0);
+ } else if (!tflag) {
+ /* syntax error: empty declaration */
+ warning(0);
+ }
+ }
+ | clrtyp deftyp notype_init_decls T_SEMI {
+ if (sflag) {
+ /* old style declaration; add "int" */
+ error(1);
+ } else if (!tflag) {
+ /* old style declaration; add "int" */
+ warning(1);
+ }
+ }
+ | declmods deftyp T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else {
+ /* empty declaration */
+ warning(2);
+ }
+ }
+ | declmods deftyp notype_init_decls T_SEMI
+ | declspecs deftyp T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else if (!dcs->d_nedecl) {
+ /* empty declaration */
+ warning(2);
+ }
+ }
+ | declspecs deftyp type_init_decls T_SEMI
+ | error T_SEMI {
+ globclup();
+ }
+ | error T_RBRACE {
+ globclup();
+ }
+ ;
+
+func_def:
+ func_decl {
+ if ($1->s_type->t_tspec != FUNC) {
+ /* syntax error */
+ error(249);
+ YYERROR;
+ }
+ if ($1->s_type->t_typedef) {
+ /* ()-less function definition */
+ error(64);
+ YYERROR;
+ }
+ funcdef($1);
+ blklev++;
+ pushdecl(ARG);
+ } opt_arg_declaration_list {
+ popdecl();
+ blklev--;
+ cluparg();
+ pushctrl(0);
+ } comp_stmnt {
+ funcend();
+ popctrl(0);
+ }
+ ;
+
+func_decl:
+ clrtyp deftyp notype_decl {
+ $$ = $3;
+ }
+ | declmods deftyp notype_decl {
+ $$ = $3;
+ }
+ | declspecs deftyp type_decl {
+ $$ = $3;
+ }
+ ;
+
+opt_arg_declaration_list:
+ /* empty */
+ | arg_declaration_list
+ ;
+
+arg_declaration_list:
+ arg_declaration
+ | arg_declaration_list arg_declaration
+ /* XXX or better "arg_declaration error" ? */
+ | error
+ ;
+
+/*
+ * "arg_declaration" is separated from "declaration" because it
+ * needs other error handling.
+ */
+
+arg_declaration:
+ declmods deftyp T_SEMI {
+ /* empty declaration */
+ warning(2);
+ }
+ | declmods deftyp notype_init_decls T_SEMI
+ | declspecs deftyp T_SEMI {
+ if (!dcs->d_nedecl) {
+ /* empty declaration */
+ warning(2);
+ } else {
+ tspec_t ts = dcs->d_type->t_tspec;
+ /* %s declared in argument declaration list */
+ warning(3, ts == STRUCT ? "struct" :
+ (ts == UNION ? "union" : "enum"));
+ }
+ }
+ | declspecs deftyp type_init_decls T_SEMI {
+ if (dcs->d_nedecl) {
+ tspec_t ts = dcs->d_type->t_tspec;
+ /* %s declared in argument declaration list */
+ warning(3, ts == STRUCT ? "struct" :
+ (ts == UNION ? "union" : "enum"));
+ }
+ }
+ | declmods error
+ | declspecs error
+ ;
+
+declaration:
+ declmods deftyp T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else {
+ /* empty declaration */
+ warning(2);
+ }
+ }
+ | declmods deftyp notype_init_decls T_SEMI
+ | declspecs deftyp T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else if (!dcs->d_nedecl) {
+ /* empty declaration */
+ warning(2);
+ }
+ }
+ | declspecs deftyp type_init_decls T_SEMI
+ | error T_SEMI
+ ;
+
+clrtyp:
+ {
+ clrtyp();
+ }
+ ;
+
+deftyp:
+ /* empty */ {
+ deftyp();
+ }
+ ;
+
+declspecs:
+ clrtyp_typespec {
+ addtype($1);
+ }
+ | declmods typespec {
+ addtype($2);
+ }
+ | declspecs declmod
+ | declspecs notype_typespec {
+ addtype($2);
+ }
+ ;
+
+declmods:
+ clrtyp T_QUAL {
+ addqual($2);
+ }
+ | clrtyp T_SCLASS {
+ addscl($2);
+ }
+ | declmods declmod
+ ;
+
+declmod:
+ T_QUAL {
+ addqual($1);
+ }
+ | T_SCLASS {
+ addscl($1);
+ }
+ ;
+
+clrtyp_typespec:
+ clrtyp notype_typespec {
+ $$ = $2;
+ }
+ | T_TYPENAME clrtyp {
+ $$ = getsym($1)->s_type;
+ }
+ ;
+
+typespec:
+ notype_typespec {
+ $$ = $1;
+ }
+ | T_TYPENAME {
+ $$ = getsym($1)->s_type;
+ }
+ ;
+
+notype_typespec:
+ T_TYPE {
+ $$ = gettyp($1);
+ }
+ | struct_spec {
+ popdecl();
+ $$ = $1;
+ }
+ | enum_spec {
+ popdecl();
+ $$ = $1;
+ }
+ ;
+
+struct_spec:
+ struct struct_tag {
+ /*
+ * STDC requires that "struct a;" always introduces
+ * a new tag if "a" is not declared at current level
+ *
+ * yychar is valid because otherwise the parser would
+ * not been able to deceide if he must shift or reduce
+ */
+ $$ = mktag($2, $1, 0, yychar == T_SEMI);
+ }
+ | struct struct_tag {
+ dcs->d_tagtyp = mktag($2, $1, 1, 0);
+ } struct_declaration {
+ $$ = compltag(dcs->d_tagtyp, $4);
+ }
+ | struct {
+ dcs->d_tagtyp = mktag(NULL, $1, 1, 0);
+ } struct_declaration {
+ $$ = compltag(dcs->d_tagtyp, $3);
+ }
+ | struct error {
+ symtyp = FVFT;
+ $$ = gettyp(INT);
+ }
+ ;
+
+struct:
+ T_SOU {
+ symtyp = FTAG;
+ pushdecl($1 == STRUCT ? MOS : MOU);
+ dcs->d_offset = 0;
+ dcs->d_stralign = CHAR_BIT;
+ $$ = $1;
+ }
+ ;
+
+struct_tag:
+ identifier {
+ $$ = getsym($1);
+ }
+ ;
+
+struct_declaration:
+ struct_decl_lbrace member_declaration_list_with_rbrace {
+ $$ = $2;
+ }
+ ;
+
+struct_decl_lbrace:
+ T_LBRACE {
+ symtyp = FVFT;
+ }
+ ;
+
+member_declaration_list_with_rbrace:
+ member_declaration_list T_SEMI T_RBRACE {
+ $$ = $1;
+ }
+ | member_declaration_list T_RBRACE {
+ if (sflag) {
+ /* syntax req. ";" after last struct/union member */
+ error(66);
+ } else {
+ /* syntax req. ";" after last struct/union member */
+ warning(66);
+ }
+ $$ = $1;
+ }
+ | T_RBRACE {
+ $$ = NULL;
+ }
+ ;
+
+member_declaration_list:
+ member_declaration {
+ $$ = $1;
+ }
+ | member_declaration_list T_SEMI member_declaration {
+ $$ = lnklst($1, $3);
+ }
+ ;
+
+member_declaration:
+ noclass_declmods deftyp {
+ /* too late, i know, but getsym() compensates it */
+ symtyp = FMOS;
+ } notype_member_decls {
+ symtyp = FVFT;
+ $$ = $4;
+ }
+ | noclass_declspecs deftyp {
+ symtyp = FMOS;
+ } type_member_decls {
+ symtyp = FVFT;
+ $$ = $4;
+ }
+ | noclass_declmods deftyp {
+ /* struct or union member must be named */
+ warning(49);
+ $$ = NULL;
+ }
+ | noclass_declspecs deftyp {
+ /* struct or union member must be named */
+ warning(49);
+ $$ = NULL;
+ }
+ | error {
+ symtyp = FVFT;
+ $$ = NULL;
+ }
+ ;
+
+noclass_declspecs:
+ clrtyp_typespec {
+ addtype($1);
+ }
+ | noclass_declmods typespec {
+ addtype($2);
+ }
+ | noclass_declspecs T_QUAL {
+ addqual($2);
+ }
+ | noclass_declspecs notype_typespec {
+ addtype($2);
+ }
+ ;
+
+noclass_declmods:
+ clrtyp T_QUAL {
+ addqual($2);
+ }
+ | noclass_declmods T_QUAL {
+ addqual($2);
+ }
+ ;
+
+notype_member_decls:
+ notype_member_decl {
+ $$ = decl1str($1);
+ }
+ | notype_member_decls {
+ symtyp = FMOS;
+ } T_COMMA type_member_decl {
+ $$ = lnklst($1, decl1str($4));
+ }
+ ;
+
+type_member_decls:
+ type_member_decl {
+ $$ = decl1str($1);
+ }
+ | type_member_decls {
+ symtyp = FMOS;
+ } T_COMMA type_member_decl {
+ $$ = lnklst($1, decl1str($4));
+ }
+ ;
+
+notype_member_decl:
+ notype_decl {
+ $$ = $1;
+ }
+ | notype_decl T_COLON constant {
+ $$ = bitfield($1, toicon($3));
+ }
+ | {
+ symtyp = FVFT;
+ } T_COLON constant {
+ $$ = bitfield(NULL, toicon($3));
+ }
+ ;
+
+type_member_decl:
+ type_decl {
+ $$ = $1;
+ }
+ | type_decl T_COLON constant {
+ $$ = bitfield($1, toicon($3));
+ }
+ | {
+ symtyp = FVFT;
+ } T_COLON constant {
+ $$ = bitfield(NULL, toicon($3));
+ }
+ ;
+
+enum_spec:
+ enum enum_tag {
+ $$ = mktag($2, ENUM, 0, 0);
+ }
+ | enum enum_tag {
+ dcs->d_tagtyp = mktag($2, ENUM, 1, 0);
+ } enum_declaration {
+ $$ = compltag(dcs->d_tagtyp, $4);
+ }
+ | enum {
+ dcs->d_tagtyp = mktag(NULL, ENUM, 1, 0);
+ } enum_declaration {
+ $$ = compltag(dcs->d_tagtyp, $3);
+ }
+ | enum error {
+ symtyp = FVFT;
+ $$ = gettyp(INT);
+ }
+ ;
+
+enum:
+ T_ENUM {
+ symtyp = FTAG;
+ pushdecl(ENUMCON);
+ }
+ ;
+
+enum_tag:
+ identifier {
+ $$ = getsym($1);
+ }
+ ;
+
+enum_declaration:
+ enum_decl_lbrace enums_with_opt_comma T_RBRACE {
+ $$ = $2;
+ }
+ ;
+
+enum_decl_lbrace:
+ T_LBRACE {
+ symtyp = FVFT;
+ enumval = 0;
+ }
+ ;
+
+enums_with_opt_comma:
+ enums {
+ $$ = $1;
+ }
+ | enums T_COMMA {
+ if (sflag) {
+ /* trailing "," prohibited in enum declaration */
+ error(54);
+ } else {
+ /* trailing "," prohibited in enum declaration */
+ warning(54);
+ }
+ $$ = $1;
+ }
+ ;
+
+enums:
+ enumerator {
+ $$ = $1;
+ }
+ | enums T_COMMA enumerator {
+ $$ = lnklst($1, $3);
+ }
+ | error {
+ $$ = NULL;
+ }
+ ;
+
+enumerator:
+ ename {
+ $$ = ename($1, enumval, 1);
+ }
+ | ename T_ASSIGN constant {
+ $$ = ename($1, toicon($3), 0);
+ }
+ ;
+
+ename:
+ identifier {
+ $$ = getsym($1);
+ }
+ ;
+
+
+notype_init_decls:
+ notype_init_decl
+ | notype_init_decls T_COMMA type_init_decl
+ ;
+
+type_init_decls:
+ type_init_decl
+ | type_init_decls T_COMMA type_init_decl
+ ;
+
+notype_init_decl:
+ notype_decl opt_asm_spec {
+ idecl($1, 0);
+ chksz($1);
+ }
+ | notype_decl opt_asm_spec {
+ idecl($1, 1);
+ } T_ASSIGN initializer {
+ chksz($1);
+ }
+ ;
+
+type_init_decl:
+ type_decl opt_asm_spec {
+ idecl($1, 0);
+ chksz($1);
+ }
+ | type_decl opt_asm_spec {
+ idecl($1, 1);
+ } T_ASSIGN initializer {
+ chksz($1);
+ }
+ ;
+
+notype_decl:
+ notype_direct_decl {
+ $$ = $1;
+ }
+ | pointer notype_direct_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+notype_direct_decl:
+ T_NAME {
+ $$ = dname(getsym($1));
+ }
+ | T_LPARN type_decl T_RPARN {
+ $$ = $2;
+ }
+ | notype_direct_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | notype_direct_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | notype_direct_decl param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+type_decl:
+ type_direct_decl {
+ $$ = $1;
+ }
+ | pointer type_direct_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+type_direct_decl:
+ identifier {
+ $$ = dname(getsym($1));
+ }
+ | T_LPARN type_decl T_RPARN {
+ $$ = $2;
+ }
+ | type_direct_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | type_direct_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | type_direct_decl param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+/*
+ * param_decl and notype_param_decl exist to avoid a conflict in
+ * argument lists. A typename enclosed in parens should always be
+ * treated as a typename, not an argument.
+ * "typedef int a; f(int (a));" is "typedef int a; f(int foo(a));"
+ * not "typedef int a; f(int a);"
+ */
+param_decl:
+ direct_param_decl {
+ $$ = $1;
+ }
+ | pointer direct_param_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+direct_param_decl:
+ identifier {
+ $$ = dname(getsym($1));
+ }
+ | T_LPARN notype_param_decl T_RPARN {
+ $$ = $2;
+ }
+ | direct_param_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | direct_param_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | direct_param_decl param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+notype_param_decl:
+ direct_notype_param_decl {
+ $$ = $1;
+ }
+ | pointer direct_notype_param_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+direct_notype_param_decl:
+ T_NAME {
+ $$ = dname(getsym($1));
+ }
+ | T_LPARN notype_param_decl T_RPARN {
+ $$ = $2;
+ }
+ | direct_notype_param_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | direct_notype_param_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | direct_notype_param_decl param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+pointer:
+ asterisk {
+ $$ = $1;
+ }
+ | asterisk type_qualifier_list {
+ $$ = mergepq($1, $2);
+ }
+ | asterisk pointer {
+ $$ = mergepq($1, $2);
+ }
+ | asterisk type_qualifier_list pointer {
+ $$ = mergepq(mergepq($1, $2), $3);
+ }
+ ;
+
+asterisk:
+ T_MULT {
+ $$ = xcalloc(1, sizeof (pqinf_t));
+ $$->p_pcnt = 1;
+ }
+ ;
+
+type_qualifier_list:
+ type_qualifier {
+ $$ = $1;
+ }
+ | type_qualifier_list type_qualifier {
+ $$ = mergepq($1, $2);
+ }
+ ;
+
+type_qualifier:
+ T_QUAL {
+ $$ = xcalloc(1, sizeof (pqinf_t));
+ if ($1 == CONST) {
+ $$->p_const = 1;
+ } else {
+ $$->p_volatile = 1;
+ }
+ }
+ ;
+
+param_list:
+ id_list_lparn identifier_list T_RPARN {
+ $$ = $2;
+ }
+ | abs_decl_param_list {
+ $$ = $1;
+ }
+ ;
+
+id_list_lparn:
+ T_LPARN {
+ blklev++;
+ pushdecl(PARG);
+ }
+ ;
+
+identifier_list:
+ T_NAME {
+ $$ = iname(getsym($1));
+ }
+ | identifier_list T_COMMA T_NAME {
+ $$ = lnklst($1, iname(getsym($3)));
+ }
+ | identifier_list error {
+ $$ = $1;
+ }
+ ;
+
+abs_decl_param_list:
+ abs_decl_lparn T_RPARN {
+ $$ = NULL;
+ }
+ | abs_decl_lparn vararg_parameter_type_list T_RPARN {
+ dcs->d_proto = 1;
+ $$ = $2;
+ }
+ | abs_decl_lparn error T_RPARN {
+ $$ = NULL;
+ }
+ ;
+
+abs_decl_lparn:
+ T_LPARN {
+ blklev++;
+ pushdecl(PARG);
+ }
+ ;
+
+vararg_parameter_type_list:
+ parameter_type_list {
+ $$ = $1;
+ }
+ | parameter_type_list T_COMMA T_ELLIPSE {
+ dcs->d_vararg = 1;
+ $$ = $1;
+ }
+ | T_ELLIPSE {
+ if (sflag) {
+ /* ANSI C requires formal parameter before "..." */
+ error(84);
+ } else if (!tflag) {
+ /* ANSI C requires formal parameter before "..." */
+ warning(84);
+ }
+ dcs->d_vararg = 1;
+ $$ = NULL;
+ }
+ ;
+
+parameter_type_list:
+ parameter_declaration opt_asm_spec {
+ $$ = $1;
+ }
+ | parameter_type_list T_COMMA parameter_declaration opt_asm_spec {
+ $$ = lnklst($1, $3);
+ }
+ ;
+
+parameter_declaration:
+ declmods deftyp {
+ $$ = decl1arg(aname(), 0);
+ }
+ | declspecs deftyp {
+ $$ = decl1arg(aname(), 0);
+ }
+ | declmods deftyp notype_param_decl {
+ $$ = decl1arg($3, 0);
+ }
+ /*
+ * param_decl is needed because of following conflict:
+ * "typedef int a; f(int (a));" could be parsed as
+ * "function with argument a of type int", or
+ * "function with an abstract argument of type function".
+ * This grammar realizes the second case.
+ */
+ | declspecs deftyp param_decl {
+ $$ = decl1arg($3, 0);
+ }
+ | declmods deftyp abs_decl {
+ $$ = decl1arg($3, 0);
+ }
+ | declspecs deftyp abs_decl {
+ $$ = decl1arg($3, 0);
+ }
+ ;
+
+opt_asm_spec:
+ /* empty */
+ | T_ASM T_LPARN T_STRING T_RPARN {
+ freeyyv(&$3, T_STRING);
+ }
+ ;
+
+initializer:
+ init_expr
+ ;
+
+init_expr:
+ expr %prec T_COMMA {
+ mkinit($1);
+ }
+ | init_lbrace init_expr_list init_rbrace
+ | init_lbrace init_expr_list T_COMMA init_rbrace
+ | error
+ ;
+
+init_expr_list:
+ init_expr %prec T_COMMA
+ | init_expr_list T_COMMA init_expr
+ ;
+
+init_lbrace:
+ T_LBRACE {
+ initlbr();
+ }
+ ;
+
+init_rbrace:
+ T_RBRACE {
+ initrbr();
+ }
+ ;
+
+type_name:
+ {
+ pushdecl(ABSTRACT);
+ } abstract_declaration {
+ popdecl();
+ $$ = $2->s_type;
+ }
+ ;
+
+abstract_declaration:
+ noclass_declmods deftyp {
+ $$ = decl1abs(aname());
+ }
+ | noclass_declspecs deftyp {
+ $$ = decl1abs(aname());
+ }
+ | noclass_declmods deftyp abs_decl {
+ $$ = decl1abs($3);
+ }
+ | noclass_declspecs deftyp abs_decl {
+ $$ = decl1abs($3);
+ }
+ ;
+
+abs_decl:
+ pointer {
+ $$ = addptr(aname(), $1);
+ }
+ | direct_abs_decl {
+ $$ = $1;
+ }
+ | pointer direct_abs_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+direct_abs_decl:
+ T_LPARN abs_decl T_RPARN {
+ $$ = $2;
+ }
+ | T_LBRACK T_RBRACK {
+ $$ = addarray(aname(), 0, 0);
+ }
+ | T_LBRACK constant T_RBRACK {
+ $$ = addarray(aname(), 1, toicon($2));
+ }
+ | direct_abs_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | direct_abs_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | abs_decl_param_list {
+ $$ = addfunc(aname(), $1);
+ popdecl();
+ blklev--;
+ }
+ | direct_abs_decl abs_decl_param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+stmnt:
+ labeled_stmnt
+ | expr_stmnt
+ | comp_stmnt
+ | selection_stmnt
+ | iteration_stmnt
+ | jump_stmnt {
+ ftflg = 0;
+ }
+ | asm_stmnt
+ ;
+
+labeled_stmnt:
+ label stmnt
+ ;
+
+label:
+ identifier T_COLON {
+ symtyp = FLAB;
+ label(T_NAME, getsym($1), NULL);
+ }
+ | T_CASE constant T_COLON {
+ label(T_CASE, NULL, $2);
+ ftflg = 1;
+ }
+ | T_DEFAULT T_COLON {
+ label(T_DEFAULT, NULL, NULL);
+ ftflg = 1;
+ }
+ ;
+
+comp_stmnt:
+ compstmnt_lbrace declaration_list opt_stmnt_list compstmnt_rbrace
+ | compstmnt_lbrace opt_stmnt_list compstmnt_rbrace
+ ;
+
+compstmnt_lbrace:
+ T_LBRACE {
+ blklev++;
+ mblklev++;
+ pushdecl(AUTO);
+ }
+ ;
+
+compstmnt_rbrace:
+ T_RBRACE {
+ popdecl();
+ freeblk();
+ mblklev--;
+ blklev--;
+ ftflg = 0;
+ }
+ ;
+
+opt_stmnt_list:
+ /* empty */
+ | stmnt_list
+ ;
+
+stmnt_list:
+ stmnt {
+ clrwflgs();
+ }
+ | stmnt_list stmnt {
+ clrwflgs();
+ }
+ | stmnt_list error T_SEMI {
+ clrwflgs();
+ }
+ ;
+
+expr_stmnt:
+ expr T_SEMI {
+ expr($1, 0, 0);
+ ftflg = 0;
+ }
+ | T_SEMI {
+ ftflg = 0;
+ }
+ ;
+
+selection_stmnt:
+ if_without_else {
+ if2();
+ if3(0);
+ }
+ | if_without_else T_ELSE {
+ if2();
+ } stmnt {
+ if3(1);
+ }
+ | if_without_else T_ELSE error {
+ if3(0);
+ }
+ | switch_expr stmnt {
+ switch2();
+ }
+ | switch_expr error {
+ switch2();
+ }
+ ;
+
+if_without_else:
+ if_expr stmnt
+ | if_expr error
+ ;
+
+if_expr:
+ T_IF T_LPARN expr T_RPARN {
+ if1($3);
+ clrwflgs();
+ }
+ ;
+
+switch_expr:
+ T_SWITCH T_LPARN expr T_RPARN {
+ switch1($3);
+ clrwflgs();
+ }
+ ;
+
+iteration_stmnt:
+ while_expr stmnt {
+ while2();
+ }
+ | while_expr error {
+ while2();
+ }
+ | do stmnt do_while_expr {
+ do2($3);
+ ftflg = 0;
+ }
+ | do error {
+ do2(NULL);
+ }
+ | for_exprs stmnt {
+ for2();
+ }
+ | for_exprs error {
+ for2();
+ }
+ ;
+
+while_expr:
+ T_WHILE T_LPARN expr T_RPARN {
+ while1($3);
+ clrwflgs();
+ }
+ ;
+
+do:
+ T_DO {
+ do1();
+ }
+ ;
+
+do_while_expr:
+ T_WHILE T_LPARN expr T_RPARN T_SEMI {
+ $$ = $3;
+ }
+ ;
+
+for_exprs:
+ T_FOR T_LPARN opt_expr T_SEMI opt_expr T_SEMI opt_expr T_RPARN {
+ for1($3, $5, $7);
+ clrwflgs();
+ }
+ ;
+
+opt_expr:
+ /* empty */ {
+ $$ = NULL;
+ }
+ | expr {
+ $$ = $1;
+ }
+ ;
+
+jump_stmnt:
+ goto identifier T_SEMI {
+ dogoto(getsym($2));
+ }
+ | goto error T_SEMI {
+ symtyp = FVFT;
+ }
+ | T_CONTINUE T_SEMI {
+ docont();
+ }
+ | T_BREAK T_SEMI {
+ dobreak();
+ }
+ | T_RETURN T_SEMI {
+ doreturn(NULL);
+ }
+ | T_RETURN expr T_SEMI {
+ doreturn($2);
+ }
+ ;
+
+goto:
+ T_GOTO {
+ symtyp = FLAB;
+ }
+ ;
+
+asm_stmnt:
+ T_ASM T_LPARN read_until_rparn T_SEMI {
+ setasm();
+ }
+ | T_ASM T_QUAL T_LPARN read_until_rparn T_SEMI {
+ setasm();
+ }
+ | T_ASM error
+ ;
+
+read_until_rparn:
+ /* empty */ {
+ ignuptorp();
+ }
+ ;
+
+declaration_list:
+ declaration {
+ clrwflgs();
+ }
+ | declaration_list declaration {
+ clrwflgs();
+ }
+ ;
+
+constant:
+ expr %prec T_COMMA {
+ $$ = $1;
+ }
+ ;
+
+expr:
+ expr T_MULT expr {
+ $$ = build(MULT, $1, $3);
+ }
+ | expr T_DIVOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_ADDOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_SHFTOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_RELOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_EQOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_AND expr {
+ $$ = build(AND, $1, $3);
+ }
+ | expr T_XOR expr {
+ $$ = build(XOR, $1, $3);
+ }
+ | expr T_OR expr {
+ $$ = build(OR, $1, $3);
+ }
+ | expr T_LOGAND expr {
+ $$ = build(LOGAND, $1, $3);
+ }
+ | expr T_LOGOR expr {
+ $$ = build(LOGOR, $1, $3);
+ }
+ | expr T_QUEST expr T_COLON expr {
+ $$ = build(QUEST, $1, build(COLON, $3, $5));
+ }
+ | expr T_ASSIGN expr {
+ $$ = build(ASSIGN, $1, $3);
+ }
+ | expr T_OPASS expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_COMMA expr {
+ $$ = build(COMMA, $1, $3);
+ }
+ | term {
+ $$ = $1;
+ }
+ ;
+
+term:
+ T_NAME {
+ /* XXX realy neccessary? */
+ if (yychar < 0)
+ yychar = yylex();
+ $$ = getnnode(getsym($1), yychar);
+ }
+ | string {
+ $$ = getsnode($1);
+ }
+ | T_CON {
+ $$ = getcnode(gettyp($1->v_tspec), $1);
+ }
+ | T_LPARN expr T_RPARN {
+ if ($2 != NULL)
+ $2->tn_parn = 1;
+ $$ = $2;
+ }
+ | term T_INCDEC {
+ $$ = build($2 == INC ? INCAFT : DECAFT, $1, NULL);
+ }
+ | T_INCDEC term {
+ $$ = build($1 == INC ? INCBEF : DECBEF, $2, NULL);
+ }
+ | T_MULT term {
+ $$ = build(STAR, $2, NULL);
+ }
+ | T_AND term {
+ $$ = build(AMPER, $2, NULL);
+ }
+ | T_UNOP term {
+ $$ = build($1, $2, NULL);
+ }
+ | T_ADDOP term {
+ if (tflag && $1 == PLUS) {
+ /* unary + is illegal in traditional C */
+ warning(100);
+ }
+ $$ = build($1 == PLUS ? UPLUS : UMINUS, $2, NULL);
+ }
+ | term T_LBRACK expr T_RBRACK {
+ $$ = build(STAR, build(PLUS, $1, $3), NULL);
+ }
+ | term T_LPARN T_RPARN {
+ $$ = funccall($1, NULL);
+ }
+ | term T_LPARN func_arg_list T_RPARN {
+ $$ = funccall($1, $3);
+ }
+ | term point_or_arrow T_NAME {
+ if ($1 != NULL) {
+ sym_t *msym;
+ /* XXX strmemb should be integrated in build() */
+ if ($2 == ARROW) {
+ /* must to this before strmemb is called */
+ $1 = cconv($1);
+ }
+ msym = strmemb($1, $2, getsym($3));
+ $$ = build($2, $1, getnnode(msym, 0));
+ } else {
+ $$ = NULL;
+ }
+ }
+ | T_SIZEOF term %prec T_SIZEOF {
+ if (($$ = $2 == NULL ? NULL : bldszof($2->tn_type)) != NULL)
+ chkmisc($2, 0, 0, 0, 0, 0, 1);
+ }
+ | T_SIZEOF T_LPARN type_name T_RPARN %prec T_SIZEOF {
+ $$ = bldszof($3);
+ }
+ | T_LPARN type_name T_RPARN term %prec T_UNOP {
+ $$ = cast($4, $2);
+ }
+ ;
+
+string:
+ T_STRING {
+ $$ = $1;
+ }
+ | T_STRING string2 {
+ $$ = catstrg($1, $2);
+ }
+ ;
+
+string2:
+ T_STRING {
+ if (tflag) {
+ /* concatenated strings are illegal in traditional C */
+ warning(219);
+ }
+ $$ = $1;
+ }
+ | string2 T_STRING {
+ $$ = catstrg($1, $2);
+ }
+ ;
+
+func_arg_list:
+ expr %prec T_COMMA {
+ $$ = funcarg(NULL, $1);
+ }
+ | func_arg_list T_COMMA expr {
+ $$ = funcarg($1, $3);
+ }
+ ;
+
+point_or_arrow:
+ T_STROP {
+ symtyp = FMOS;
+ $$ = $1;
+ }
+ ;
+
+identifier:
+ T_NAME {
+ $$ = $1;
+ }
+ | T_TYPENAME {
+ $$ = $1;
+ }
+ ;
+
+%%
+
+/* ARGSUSED */
+int
+yyerror(msg)
+ char *msg;
+{
+ error(249);
+ if (++sytxerr >= 5)
+ norecover();
+ return (0);
+}
+
+/*
+ * Gets a node for a constant and returns the value of this constant
+ * as integer.
+ * Is the node not constant or too large for int or of type float,
+ * a warning will be printed.
+ *
+ * toicon() should be used only inside declarations. If it is used in
+ * expressions, it frees the memory used for the expression.
+ */
+static int
+toicon(tn)
+ tnode_t *tn;
+{
+ int i;
+ tspec_t t;
+ val_t *v;
+
+ v = constant(tn);
+
+ /*
+ * Abstract declarations are used inside expression. To free
+ * the memory would be a fatal error.
+ */
+ if (dcs->d_ctx != ABSTRACT)
+ tfreeblk();
+
+ if ((t = v->v_tspec) == FLOAT || t == DOUBLE || t == LDOUBLE) {
+ i = (int)v->v_ldbl;
+ /* integral constant expression expected */
+ error(55);
+ } else {
+ i = (int)v->v_quad;
+ if (isutyp(t)) {
+ if ((u_quad_t)v->v_quad > INT_MAX) {
+ /* integral constant too large */
+ warning(56);
+ }
+ } else {
+ if (v->v_quad > INT_MAX || v->v_quad < INT_MIN) {
+ /* integral constant too large */
+ warning(56);
+ }
+ }
+ }
+ free(v);
+ return (i);
+}
+
+static void
+idecl(decl, initflg)
+ sym_t *decl;
+ int initflg;
+{
+ initerr = 0;
+ initsym = decl;
+
+ switch (dcs->d_ctx) {
+ case EXTERN:
+ decl1ext(decl, initflg);
+ break;
+ case ARG:
+ (void)decl1arg(decl, initflg);
+ break;
+ case AUTO:
+ decl1loc(decl, initflg);
+ break;
+ default:
+ lerror("idecl()");
+ }
+
+ if (initflg && !initerr)
+ prepinit();
+}
+
+/*
+ * Discard all input tokens up to and including the next
+ * unmatched right paren
+ */
+void
+ignuptorp()
+{
+ int level;
+
+ if (yychar < 0)
+ yychar = yylex();
+ freeyyv(&yylval, yychar);
+
+ level = 1;
+ while (yychar != T_RPARN || --level > 0) {
+ if (yychar == T_LPARN) {
+ level++;
+ } else if (yychar <= 0) {
+ break;
+ }
+ freeyyv(&yylval, yychar = yylex());
+ }
+
+ yyclearin;
+}
diff --git a/usr.bin/xlint/lint1/decl.c b/usr.bin/xlint/lint1/decl.c
new file mode 100644
index 0000000..fa023b7
--- /dev/null
+++ b/usr.bin/xlint/lint1/decl.c
@@ -0,0 +1,3134 @@
+/* $NetBSD: decl.c,v 1.11 1995/10/02 17:34:16 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: decl.c,v 1.11 1995/10/02 17:34:16 jpo Exp $";
+#endif
+
+#include <sys/param.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lint1.h"
+
+const char *unnamed = "<unnamed>";
+
+/* contains various information and classification on types */
+ttab_t ttab[NTSPEC];
+
+/* shared type structures for arithmtic types and void */
+static type_t *typetab;
+
+/* value of next enumerator during declaration of enum types */
+int enumval;
+
+/*
+ * pointer to top element of a stack which contains informations local
+ * to nested declarations
+ */
+dinfo_t *dcs;
+
+static type_t *tdeferr __P((type_t *, tspec_t));
+static void settdsym __P((type_t *, sym_t *));
+static tspec_t mrgtspec __P((tspec_t, tspec_t));
+static void align __P((int, int));
+static sym_t *newtag __P((sym_t *, scl_t, int, int));
+static int eqargs __P((type_t *, type_t *, int *));
+static int mnoarg __P((type_t *, int *));
+static int chkosdef __P((sym_t *, sym_t *));
+static int chkptdecl __P((sym_t *, sym_t *));
+static sym_t *nsfunc __P((sym_t *, sym_t *));
+static void osfunc __P((sym_t *, sym_t *));
+static void ledecl __P((sym_t *));
+static int chkinit __P((sym_t *));
+static void chkausg __P((int, sym_t *));
+static void chkvusg __P((int, sym_t *));
+static void chklusg __P((sym_t *));
+static void chktusg __P((sym_t *));
+static void chkglvar __P((sym_t *));
+static void glchksz __P((sym_t *));
+
+/*
+ * initializes all global vars used in declarations
+ */
+void
+initdecl()
+{
+ int i;
+ static struct {
+ tspec_t it_tspec;
+ ttab_t it_ttab;
+ } ittab[] = {
+ { SIGNED, { 0, 0,
+ SIGNED, UNSIGN,
+ 0, 0, 0, 0, 0, "signed" } },
+ { UNSIGN, { 0, 0,
+ SIGNED, UNSIGN,
+ 0, 0, 0, 0, 0, "unsigned" } },
+ { CHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 0, 0, 1, 1, "char" } },
+ { SCHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 0, 0, 1, 1, "signed char" } },
+ { UCHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 1, 0, 1, 1, "unsigned char" } },
+ { SHORT, { sizeof (short) * CHAR_BIT, 2 * CHAR_BIT,
+ SHORT, USHORT,
+ 1, 0, 0, 1, 1, "short" } },
+ { USHORT, { sizeof (u_short) * CHAR_BIT, 2 * CHAR_BIT,
+ SHORT, USHORT,
+ 1, 1, 0, 1, 1, "unsigned short" } },
+ { INT, { sizeof (int) * CHAR_BIT, 3 * CHAR_BIT,
+ INT, UINT,
+ 1, 0, 0, 1, 1, "int" } },
+ { UINT, { sizeof (u_int) * CHAR_BIT, 3 * CHAR_BIT,
+ INT, UINT,
+ 1, 1, 0, 1, 1, "unsigned int" } },
+ { LONG, { sizeof (long) * CHAR_BIT, 4 * CHAR_BIT,
+ LONG, ULONG,
+ 1, 0, 0, 1, 1, "long" } },
+ { ULONG, { sizeof (u_long) * CHAR_BIT, 4 * CHAR_BIT,
+ LONG, ULONG,
+ 1, 1, 0, 1, 1, "unsigned long" } },
+ { QUAD, { sizeof (quad_t) * CHAR_BIT, 8 * CHAR_BIT,
+ QUAD, UQUAD,
+ 1, 0, 0, 1, 1, "long long" } },
+ { UQUAD, { sizeof (u_quad_t) * CHAR_BIT, 8 * CHAR_BIT,
+ QUAD, UQUAD,
+ 1, 1, 0, 1, 1, "unsigned long long" } },
+ { FLOAT, { sizeof (float) * CHAR_BIT, 4 * CHAR_BIT,
+ FLOAT, FLOAT,
+ 0, 0, 1, 1, 1, "float" } },
+ { DOUBLE, { sizeof (double) * CHAR_BIT, 8 * CHAR_BIT,
+ DOUBLE, DOUBLE,
+ 0, 0, 1, 1, 1, "double" } },
+ { LDOUBLE, { sizeof (ldbl_t) * CHAR_BIT, 10 * CHAR_BIT,
+ LDOUBLE, LDOUBLE,
+ 0, 0, 1, 1, 1, "long double" } },
+ { VOID, { -1, -1,
+ VOID, VOID,
+ 0, 0, 0, 0, 0, "void" } },
+ { STRUCT, { -1, -1,
+ STRUCT, STRUCT,
+ 0, 0, 0, 0, 0, "struct" } },
+ { UNION, { -1, -1,
+ UNION, UNION,
+ 0, 0, 0, 0, 0, "union" } },
+ { ENUM, { sizeof (int) * CHAR_BIT, 3 * CHAR_BIT,
+ ENUM, ENUM,
+ 1, 0, 0, 1, 1, "enum" } },
+ { PTR, { sizeof (void *) * CHAR_BIT, 4 * CHAR_BIT,
+ PTR, PTR,
+ 0, 1, 0, 0, 1, "pointer" } },
+ { ARRAY, { -1, -1,
+ ARRAY, ARRAY,
+ 0, 0, 0, 0, 0, "array" } },
+ { FUNC, { -1, -1,
+ FUNC, FUNC,
+ 0, 0, 0, 0, 0, "function" } },
+ };
+
+ /* declaration stack */
+ dcs = xcalloc(1, sizeof (dinfo_t));
+ dcs->d_ctx = EXTERN;
+ dcs->d_ldlsym = &dcs->d_dlsyms;
+
+ /* type information and classification */
+ for (i = 0; i < sizeof (ittab) / sizeof (ittab[0]); i++)
+ STRUCT_ASSIGN(ttab[ittab[i].it_tspec], ittab[i].it_ttab);
+ if (!pflag) {
+ for (i = 0; i < NTSPEC; i++)
+ ttab[i].tt_psz = ttab[i].tt_sz;
+ }
+
+ /* shared type structures */
+ typetab = xcalloc(NTSPEC, sizeof (type_t));
+ for (i = 0; i < NTSPEC; i++)
+ typetab[i].t_tspec = NOTSPEC;
+ typetab[CHAR].t_tspec = CHAR;
+ typetab[SCHAR].t_tspec = SCHAR;
+ typetab[UCHAR].t_tspec = UCHAR;
+ typetab[SHORT].t_tspec = SHORT;
+ typetab[USHORT].t_tspec = USHORT;
+ typetab[INT].t_tspec = INT;
+ typetab[UINT].t_tspec = UINT;
+ typetab[LONG].t_tspec = LONG;
+ typetab[ULONG].t_tspec = ULONG;
+ typetab[QUAD].t_tspec = QUAD;
+ typetab[UQUAD].t_tspec = UQUAD;
+ typetab[FLOAT].t_tspec = FLOAT;
+ typetab[DOUBLE].t_tspec = DOUBLE;
+ typetab[LDOUBLE].t_tspec = LDOUBLE;
+ typetab[VOID].t_tspec = VOID;
+ /*
+ * Next two are not real types. They are only used by the parser
+ * to return keywords "signed" and "unsigned"
+ */
+ typetab[SIGNED].t_tspec = SIGNED;
+ typetab[UNSIGN].t_tspec = UNSIGN;
+}
+
+/*
+ * Returns a shared type structure vor arithmetic types and void.
+ *
+ * It's important do duplicate this structure (using duptyp() or tdupdyp())
+ * if it is to be modified (adding qualifiers or anything else).
+ */
+type_t *
+gettyp(t)
+ tspec_t t;
+{
+ return (&typetab[t]);
+}
+
+type_t *
+duptyp(tp)
+ const type_t *tp;
+{
+ type_t *ntp;
+
+ ntp = getblk(sizeof (type_t));
+ STRUCT_ASSIGN(*ntp, *tp);
+ return (ntp);
+}
+
+/*
+ * Use tduptyp() instead of duptyp() inside expressions (if the
+ * allocated memory should be freed after the expr).
+ */
+type_t *
+tduptyp(tp)
+ const type_t *tp;
+{
+ type_t *ntp;
+
+ ntp = tgetblk(sizeof (type_t));
+ STRUCT_ASSIGN(*ntp, *tp);
+ return (ntp);
+}
+
+/*
+ * Returns 1 if the argument is void or an incomplete array,
+ * struct, union or enum type.
+ */
+int
+incompl(tp)
+ type_t *tp;
+{
+ tspec_t t;
+
+ if ((t = tp->t_tspec) == VOID) {
+ return (1);
+ } else if (t == ARRAY) {
+ return (tp->t_aincompl);
+ } else if (t == STRUCT || t == UNION) {
+ return (tp->t_str->sincompl);
+ } else if (t == ENUM) {
+ return (tp->t_enum->eincompl);
+ }
+ return (0);
+}
+
+/*
+ * Set the flag for (in)complete array, struct, union or enum
+ * types.
+ */
+void
+setcompl(tp, ic)
+ type_t *tp;
+ int ic;
+{
+ tspec_t t;
+
+ if ((t = tp->t_tspec) == ARRAY) {
+ tp->t_aincompl = ic;
+ } else if (t == STRUCT || t == UNION) {
+ tp->t_str->sincompl = ic;
+ } else {
+ if (t != ENUM)
+ lerror("setcompl() 1");
+ tp->t_enum->eincompl = ic;
+ }
+}
+
+/*
+ * Remember the storage class of the current declaration in dcs->d_scl
+ * (the top element of the declaration stack) and detect multiple
+ * storage classes.
+ */
+void
+addscl(sc)
+ scl_t sc;
+{
+ if (sc == INLINE) {
+ if (dcs->d_inline)
+ /* duplicate '%s' */
+ warning(10, "inline");
+ dcs->d_inline = 1;
+ return;
+ }
+ if (dcs->d_type != NULL || dcs->d_atyp != NOTSPEC ||
+ dcs->d_smod != NOTSPEC || dcs->d_lmod != NOTSPEC) {
+ /* storage class after type is obsolescent */
+ warning(83);
+ }
+ if (dcs->d_scl == NOSCL) {
+ dcs->d_scl = sc;
+ } else {
+ /*
+ * multiple storage classes. An error will be reported in
+ * deftyp().
+ */
+ dcs->d_mscl = 1;
+ }
+}
+
+/*
+ * Remember the type, modifier or typedef name returned by the parser
+ * in *dcs (top element of decl stack). This information is used in
+ * deftyp() to build the type used for all declarators in this
+ * declaration.
+ *
+ * Is tp->t_typedef 1, the type comes from a previously defined typename.
+ * Otherwise it comes from a type specifier (int, long, ...) or a
+ * struct/union/enum tag.
+ */
+void
+addtype(tp)
+ type_t *tp;
+{
+ tspec_t t;
+
+ if (tp->t_typedef) {
+ if (dcs->d_type != NULL || dcs->d_atyp != NOTSPEC ||
+ dcs->d_lmod != NOTSPEC || dcs->d_smod != NOTSPEC) {
+ /*
+ * something like "typedef int a; int a b;"
+ * This should not happen with current grammar.
+ */
+ lerror("addtype()");
+ }
+ dcs->d_type = tp;
+ return;
+ }
+
+ t = tp->t_tspec;
+
+ if (t == STRUCT || t == UNION || t == ENUM) {
+ /*
+ * something like "int struct a ..."
+ * struct/union/enum with anything else is not allowed
+ */
+ if (dcs->d_type != NULL || dcs->d_atyp != NOTSPEC ||
+ dcs->d_lmod != NOTSPEC || dcs->d_smod != NOTSPEC) {
+ /*
+ * remember that an error must be reported in
+ * deftyp().
+ */
+ dcs->d_terr = 1;
+ dcs->d_atyp = dcs->d_lmod = dcs->d_smod = NOTSPEC;
+ }
+ dcs->d_type = tp;
+ return;
+ }
+
+ if (dcs->d_type != NULL && !dcs->d_type->t_typedef) {
+ /*
+ * something like "struct a int"
+ * struct/union/enum with anything else is not allowed
+ */
+ dcs->d_terr = 1;
+ return;
+ }
+
+ if (t == LONG && dcs->d_lmod == LONG) {
+ /* "long long" or "long ... long" */
+ t = QUAD;
+ dcs->d_lmod = NOTSPEC;
+ if (!quadflg)
+ /* %s C does not support 'long long' */
+ (void)gnuism(265, tflag ? "traditional" : "ANSI");
+ }
+
+ if (dcs->d_type != NULL && dcs->d_type->t_typedef) {
+ /* something like "typedef int a; a long ..." */
+ dcs->d_type = tdeferr(dcs->d_type, t);
+ return;
+ }
+
+ /* now it can be only a combination of arithmetic types and void */
+ if (t == SIGNED || t == UNSIGN) {
+ /* remeber specifiers "signed" and "unsigned" in dcs->d_smod */
+ if (dcs->d_smod != NOTSPEC)
+ /*
+ * more then one "signed" and/or "unsigned"; print
+ * an error in deftyp()
+ */
+ dcs->d_terr = 1;
+ dcs->d_smod = t;
+ } else if (t == SHORT || t == LONG || t == QUAD) {
+ /*
+ * remember specifiers "short", "long" and "long long" in
+ * dcs->d_lmod
+ */
+ if (dcs->d_lmod != NOTSPEC)
+ /* more than one, print error in deftyp() */
+ dcs->d_terr = 1;
+ dcs->d_lmod = t;
+ } else {
+ /*
+ * remember specifiers "void", "char", "int", "float" or
+ * "double" int dcs->d_atyp
+ */
+ if (dcs->d_atyp != NOTSPEC)
+ /* more than one, print error in deftyp() */
+ dcs->d_terr = 1;
+ dcs->d_atyp = t;
+ }
+}
+
+/*
+ * called if a list of declaration specifiers contains a typedef name
+ * and other specifiers (except struct, union, enum, typedef name)
+ */
+static type_t *
+tdeferr(td, t)
+ type_t *td;
+ tspec_t t;
+{
+ tspec_t t2;
+
+ t2 = td->t_tspec;
+
+ switch (t) {
+ case SIGNED:
+ case UNSIGN:
+ if (t2 == CHAR || t2 == SHORT || t2 == INT || t2 == LONG ||
+ t2 == QUAD) {
+ if (!tflag)
+ /* modifying typedef with ... */
+ warning(5, ttab[t].tt_name);
+ td = duptyp(gettyp(mrgtspec(t2, t)));
+ td->t_typedef = 1;
+ return (td);
+ }
+ break;
+ case SHORT:
+ if (t2 == INT || t2 == UINT) {
+ /* modifying typedef with ... */
+ warning(5, "short");
+ td = duptyp(gettyp(t2 == INT ? SHORT : USHORT));
+ td->t_typedef = 1;
+ return (td);
+ }
+ break;
+ case LONG:
+ if (t2 == INT || t2 == UINT || t2 == LONG || t2 == ULONG ||
+ t2 == FLOAT || t2 == DOUBLE) {
+ /* modifying typedef with ... */
+ warning(5, "long");
+ if (t2 == INT) {
+ td = gettyp(LONG);
+ } else if (t2 == UINT) {
+ td = gettyp(ULONG);
+ } else if (t2 == LONG) {
+ td = gettyp(QUAD);
+ } else if (t2 == ULONG) {
+ td = gettyp(UQUAD);
+ } else if (t2 == FLOAT) {
+ td = gettyp(DOUBLE);
+ } else if (t2 == DOUBLE) {
+ td = gettyp(LDOUBLE);
+ }
+ td = duptyp(td);
+ td->t_typedef = 1;
+ return (td);
+ }
+ break;
+ /* LINTED (enumeration values not handled in switch) */
+ }
+
+ /* Anything other is not accepted. */
+
+ dcs->d_terr = 1;
+ return (td);
+}
+
+/*
+ * Remember the symbol of a typedef name (2nd arg) in a struct, union
+ * or enum tag if the typedef name is the first defined for this tag.
+ *
+ * If the tag is unnamed, the typdef name is used for identification
+ * of this tag in lint2. Although its possible that more then one typedef
+ * name is defined for one tag, the first name defined should be unique
+ * if the tag is unnamed.
+ */
+static void
+settdsym(tp, sym)
+ type_t *tp;
+ sym_t *sym;
+{
+ tspec_t t;
+
+ if ((t = tp->t_tspec) == STRUCT || t == UNION) {
+ if (tp->t_str->stdef == NULL)
+ tp->t_str->stdef = sym;
+ } else if (t == ENUM) {
+ if (tp->t_enum->etdef == NULL)
+ tp->t_enum->etdef = sym;
+ }
+}
+
+/*
+ * Remember a qualifier which is part of the declaration specifiers
+ * (and not the declarator) in the top element of the declaration stack.
+ * Also detect multiple qualifiers of the same kind.
+
+ * The rememberd qualifier is used by deftyp() to construct the type
+ * for all declarators.
+ */
+void
+addqual(q)
+ tqual_t q;
+{
+ if (q == CONST) {
+ if (dcs->d_const) {
+ /* duplicate "%s" */
+ warning(10, "const");
+ }
+ dcs->d_const = 1;
+ } else {
+ if (q != VOLATILE)
+ lerror("addqual() 1");
+ if (dcs->d_volatile) {
+ /* duplicate "%s" */
+ warning(10, "volatile");
+ }
+ dcs->d_volatile = 1;
+ }
+}
+
+/*
+ * Go to the next declaration level (structs, nested structs, blocks,
+ * argument declaration lists ...)
+ */
+void
+pushdecl(sc)
+ scl_t sc;
+{
+ dinfo_t *di;
+
+ if (dflag)
+ (void)printf("pushdecl(%d)\n", (int)sc);
+
+ /* put a new element on the declaration stack */
+ di = xcalloc(1, sizeof (dinfo_t));
+ di->d_nxt = dcs;
+ dcs = di;
+ di->d_ctx = sc;
+ di->d_ldlsym = &di->d_dlsyms;
+}
+
+/*
+ * Go back to previous declaration level
+ */
+void
+popdecl()
+{
+ dinfo_t *di;
+
+ if (dflag)
+ (void)printf("popdecl(%d)\n", (int)dcs->d_ctx);
+
+ if (dcs->d_nxt == NULL)
+ lerror("popdecl() 1");
+ di = dcs;
+ dcs = di->d_nxt;
+ switch (di->d_ctx) {
+ case EXTERN:
+ /* there is nothing after external declarations */
+ lerror("popdecl() 2");
+ /* NOTREACHED */
+ case MOS:
+ case MOU:
+ case ENUMCON:
+ /*
+ * Symbols declared in (nested) structs or enums are
+ * part of the next level (they are removed from the
+ * symbol table if the symbols of the outher level are
+ * removed)
+ */
+ if ((*dcs->d_ldlsym = di->d_dlsyms) != NULL)
+ dcs->d_ldlsym = di->d_ldlsym;
+ break;
+ case ARG:
+ /*
+ * All symbols in dcs->d_dlsyms are introduced in old style
+ * argument declarations (it's not clean, but possible).
+ * They are appended to the list of symbols declared in
+ * an old style argument identifier list or a new style
+ * parameter type list.
+ */
+ if (di->d_dlsyms != NULL) {
+ *di->d_ldlsym = dcs->d_fpsyms;
+ dcs->d_fpsyms = di->d_dlsyms;
+ }
+ break;
+ case ABSTRACT:
+ /*
+ * casts and sizeof
+ * Append all symbols declared in the abstract declaration
+ * to the list of symbols declared in the surounding decl.
+ * or block.
+ * XXX I'm not sure whether they should be removed from the
+ * symbol table now or later.
+ */
+ if ((*dcs->d_ldlsym = di->d_dlsyms) != NULL)
+ dcs->d_ldlsym = di->d_ldlsym;
+ break;
+ case AUTO:
+ /* check usage of local vars */
+ chkusage(di);
+ /* FALLTHROUGH */
+ case PARG:
+ /* usage of arguments will be checked by funcend() */
+ rmsyms(di->d_dlsyms);
+ break;
+ default:
+ lerror("popdecl() 3");
+ }
+ free(di);
+}
+
+/*
+ * Set flag d_asm in all declaration stack elements up to the
+ * outermost one.
+ *
+ * This is used to mark compound statements which have, possibly in
+ * nested compound statements, asm statements. For these compound
+ * statements no warnings about unused or unitialized variables are
+ * printed.
+ *
+ * There is no need to clear d_asm in dinfo structs with context AUTO,
+ * because these structs are freed at the end of the compound statement.
+ * But it must be cleard in the outermost dinfo struct, which has
+ * context EXTERN. This could be done in clrtyp() and would work for
+ * C, but not for C++ (due to mixed statements and declarations). Thus
+ * we clear it in glclup(), which is used to do some cleanup after
+ * global declarations/definitions.
+ */
+void
+setasm()
+{
+ dinfo_t *di;
+
+ for (di = dcs; di != NULL; di = di->d_nxt)
+ di->d_asm = 1;
+}
+
+/*
+ * Clean all elements of the top element of declaration stack which
+ * will be used by the next declaration
+ */
+void
+clrtyp()
+{
+ dcs->d_atyp = dcs->d_smod = dcs->d_lmod = NOTSPEC;
+ dcs->d_scl = NOSCL;
+ dcs->d_type = NULL;
+ dcs->d_const = dcs->d_volatile = 0;
+ dcs->d_inline = 0;
+ dcs->d_mscl = dcs->d_terr = 0;
+ dcs->d_nedecl = 0;
+ dcs->d_notyp = 0;
+}
+
+/*
+ * Create a type structure from the informations gathered in
+ * the declaration stack.
+ * Complain about storage classes which are not possible in current
+ * context.
+ */
+void
+deftyp()
+{
+ tspec_t t, s, l;
+ type_t *tp;
+ scl_t scl;
+
+ t = dcs->d_atyp; /* CHAR, INT, FLOAT, DOUBLE, VOID */
+ s = dcs->d_smod; /* SIGNED, UNSIGNED */
+ l = dcs->d_lmod; /* SHORT, LONG, QUAD */
+ tp = dcs->d_type;
+ scl = dcs->d_scl;
+
+ if (t == NOTSPEC && s == NOTSPEC && l == NOTSPEC && tp == NULL)
+ dcs->d_notyp = 1;
+
+ if (tp != NULL && (t != NOTSPEC || s != NOTSPEC || l != NOTSPEC)) {
+ /* should never happen */
+ lerror("deftyp() 1");
+ }
+
+ if (tp == NULL) {
+ switch (t) {
+ case NOTSPEC:
+ t = INT;
+ /* FALLTHROUGH */
+ case INT:
+ if (s == NOTSPEC)
+ s = SIGNED;
+ break;
+ case CHAR:
+ if (l != NOTSPEC) {
+ dcs->d_terr = 1;
+ l = NOTSPEC;
+ }
+ break;
+ case FLOAT:
+ if (l == LONG) {
+ l = NOTSPEC;
+ t = DOUBLE;
+ if (!tflag)
+ /* use 'double' instead of ... */
+ warning(6);
+ }
+ break;
+ case DOUBLE:
+ if (l == LONG) {
+ l = NOTSPEC;
+ t = LDOUBLE;
+ if (tflag)
+ /* 'long double' is illegal in ... */
+ warning(266);
+ }
+ break;
+ case VOID:
+ break;
+ default:
+ lerror("deftyp() 2");
+ }
+ if (t != INT && t != CHAR && (s != NOTSPEC || l != NOTSPEC)) {
+ dcs->d_terr = 1;
+ l = s = NOTSPEC;
+ }
+ if (l != NOTSPEC)
+ t = l;
+ dcs->d_type = gettyp(mrgtspec(t, s));
+ }
+
+ if (dcs->d_mscl) {
+ /* only one storage class allowed */
+ error(7);
+ }
+ if (dcs->d_terr) {
+ /* illegal type combination */
+ error(4);
+ }
+
+ if (dcs->d_ctx == EXTERN) {
+ if (scl == REG || scl == AUTO) {
+ /* illegal storage class */
+ error(8);
+ scl = NOSCL;
+ }
+ } else if (dcs->d_ctx == ARG || dcs->d_ctx == PARG) {
+ if (scl != NOSCL && scl != REG) {
+ /* only "register" valid ... */
+ error(9);
+ scl = NOSCL;
+ }
+ }
+
+ dcs->d_scl = scl;
+
+ if (dcs->d_const && dcs->d_type->t_const) {
+ if (!dcs->d_type->t_typedef)
+ lerror("deftyp() 3");
+ /* typedef already qualified with "%s" */
+ warning(68, "const");
+ }
+ if (dcs->d_volatile && dcs->d_type->t_volatile) {
+ if (!dcs->d_type->t_typedef)
+ lerror("deftyp() 4");
+ /* typedef already qualified with "%s" */
+ warning(68, "volatile");
+ }
+
+ if (dcs->d_const || dcs->d_volatile) {
+ dcs->d_type = duptyp(dcs->d_type);
+ dcs->d_type->t_const |= dcs->d_const;
+ dcs->d_type->t_volatile |= dcs->d_volatile;
+ }
+}
+
+/*
+ * Merge type specifiers (char, ..., long long, signed, unsigned).
+ */
+static tspec_t
+mrgtspec(t, s)
+ tspec_t t, s;
+{
+ if (s == SIGNED || s == UNSIGN) {
+ if (t == CHAR) {
+ t = s == SIGNED ? SCHAR : UCHAR;
+ } else if (t == SHORT) {
+ t = s == SIGNED ? SHORT : USHORT;
+ } else if (t == INT) {
+ t = s == SIGNED ? INT : UINT;
+ } else if (t == LONG) {
+ t = s == SIGNED ? LONG : ULONG;
+ } else if (t == QUAD) {
+ t = s == SIGNED ? QUAD : UQUAD;
+ }
+ }
+
+ return (t);
+}
+
+/*
+ * Return the length of a type in bit.
+ *
+ * Printing a message if the outhermost dimension of an array is 0 must
+ * be done by the caller. All other problems are reported by length()
+ * if name is not NULL.
+ */
+int
+length(tp, name)
+ type_t *tp;
+ const char *name;
+{
+ int elem, elsz;
+
+ elem = 1;
+ while (tp->t_tspec == ARRAY) {
+ elem *= tp->t_dim;
+ tp = tp->t_subt;
+ }
+ switch (tp->t_tspec) {
+ case FUNC:
+ /* compiler takes size of function */
+ lerror(msgs[12]);
+ /* NOTREACHED */
+ case STRUCT:
+ case UNION:
+ if (incompl(tp) && name != NULL) {
+ /* incomplete structure or union %s: %s */
+ error(31, tp->t_str->stag->s_name, name);
+ }
+ elsz = tp->t_str->size;
+ break;
+ case ENUM:
+ if (incompl(tp) && name != NULL) {
+ /* incomplete enum type: %s */
+ warning(13, name);
+ }
+ /* FALLTHROUGH */
+ default:
+ elsz = size(tp->t_tspec);
+ if (elsz <= 0)
+ lerror("length()");
+ break;
+ }
+ return (elem * elsz);
+}
+
+/*
+ * Get the alignment of the given Type in bits.
+ */
+int
+getbound(tp)
+ type_t *tp;
+{
+ int a;
+ tspec_t t;
+
+ while (tp->t_tspec == ARRAY)
+ tp = tp->t_subt;
+
+ if ((t = tp->t_tspec) == STRUCT || t == UNION) {
+ a = tp->t_str->align;
+ } else if (t == FUNC) {
+ /* compiler takes alignment of function */
+ error(14);
+ a = ALIGN(1) * CHAR_BIT;
+ } else {
+ if ((a = size(t)) == 0) {
+ a = CHAR_BIT;
+ } else if (a > ALIGN(1) * CHAR_BIT) {
+ a = ALIGN(1) * CHAR_BIT;
+ }
+ }
+ if (a < CHAR_BIT || a > ALIGN(1) * CHAR_BIT)
+ lerror("getbound() 1");
+ return (a);
+}
+
+/*
+ * Concatenate two lists of symbols by s_nxt. Used by declarations of
+ * struct/union/enum elements and parameters.
+ */
+sym_t *
+lnklst(l1, l2)
+ sym_t *l1, *l2;
+{
+ sym_t *l;
+
+ if ((l = l1) == NULL)
+ return (l2);
+ while (l1->s_nxt != NULL)
+ l1 = l1->s_nxt;
+ l1->s_nxt = l2;
+ return (l);
+}
+
+/*
+ * Check if the type of the given symbol is valid and print an error
+ * message if it is not.
+ *
+ * Invalid types are:
+ * - arrays of incomlete types or functions
+ * - functions returning arrays or functions
+ * - void types other than type of function or pointer
+ */
+void
+chktyp(sym)
+ sym_t *sym;
+{
+ tspec_t to, t;
+ type_t **tpp, *tp;
+
+ tpp = &sym->s_type;
+ to = NOTSPEC;
+ while ((tp = *tpp) != NULL) {
+ t = tp->t_tspec;
+ /*
+ * If this is the type of an old style function definition,
+ * a better warning is printed in funcdef().
+ */
+ if (t == FUNC && !tp->t_proto &&
+ !(to == NOTSPEC && sym->s_osdef)) {
+ if (sflag && hflag)
+ /* function declaration is not a prototype */
+ warning(287);
+ }
+ if (to == FUNC) {
+ if (t == FUNC || t == ARRAY) {
+ /* function returns illegal type */
+ error(15);
+ if (t == FUNC) {
+ *tpp = incref(*tpp, PTR);
+ } else {
+ *tpp = incref((*tpp)->t_subt, PTR);
+ }
+ return;
+ } else if (tp->t_const || tp->t_volatile) {
+ if (sflag) { /* XXX oder better !tflag ? */
+ /* function cannot return const... */
+ warning(228);
+ }
+ }
+ } if (to == ARRAY) {
+ if (t == FUNC) {
+ /* array of function is illegal */
+ error(16);
+ *tpp = gettyp(INT);
+ return;
+ } else if (t == ARRAY && tp->t_dim == 0) {
+ /* null dimension */
+ error(17);
+ return;
+ } else if (t == VOID) {
+ /* illegal use of void */
+ error(18);
+ *tpp = gettyp(INT);
+#if 0 /* errors are produced by length() */
+ } else if (incompl(tp)) {
+ /* array of incomplete type */
+ if (sflag) {
+ error(301);
+ } else {
+ warning(301);
+ }
+#endif
+ }
+ } else if (to == NOTSPEC && t == VOID) {
+ if (dcs->d_ctx == PARG) {
+ if (sym->s_scl != ABSTRACT) {
+ if (sym->s_name == unnamed)
+ lerror("chktyp()");
+ /* void param cannot have name: %s */
+ error(61, sym->s_name);
+ *tpp = gettyp(INT);
+ }
+ } else if (dcs->d_ctx == ABSTRACT) {
+ /* ok */
+ } else if (sym->s_scl != TYPEDEF) {
+ /* void type for %s */
+ error(19, sym->s_name);
+ *tpp = gettyp(INT);
+ }
+ }
+ if (t == VOID && to != PTR) {
+ if (tp->t_const || tp->t_volatile) {
+ /* inappropriate qualifiers with "void" */
+ warning(69);
+ tp->t_const = tp->t_volatile = 0;
+ }
+ }
+ tpp = &tp->t_subt;
+ to = t;
+ }
+}
+
+/*
+ * Process the declarator of a struct/union element.
+ */
+sym_t *
+decl1str(dsym)
+ sym_t *dsym;
+{
+ type_t *tp;
+ tspec_t t;
+ int sz, o, len;
+ scl_t sc;
+
+ if ((sc = dsym->s_scl) != MOS && sc != MOU)
+ lerror("decl1str() 1");
+
+ if (dcs->d_rdcsym != NULL) {
+ if ((sc = dcs->d_rdcsym->s_scl) != MOS && sc != MOU)
+ /* should be ensured by storesym() */
+ lerror("decl1str() 2");
+ if (dsym->s_styp == dcs->d_rdcsym->s_styp) {
+ /* duplicate member name: %s */
+ error(33, dsym->s_name);
+ rmsym(dcs->d_rdcsym);
+ }
+ }
+
+ chktyp(dsym);
+
+ t = (tp = dsym->s_type)->t_tspec;
+
+ if (dsym->s_field) {
+ /*
+ * bit field
+ *
+ * only unsigned und signed int are protable bit-field types
+ *(at least in ANSI C, in traditional C only unsigned int)
+ */
+ if (t == CHAR || t == UCHAR || t == SCHAR ||
+ t == SHORT || t == USHORT || t == ENUM) {
+ if (sflag) {
+ /* bit-field type '%s' invalid in ANSI C */
+ warning(273, tyname(tp));
+ } else if (pflag) {
+ /* nonportable bit-field type */
+ warning(34);
+ }
+ } else if (t == INT && dcs->d_smod == NOTSPEC) {
+ if (pflag) {
+ /* nonportable bit-field type */
+ warning(34);
+ }
+ } else if (t != INT && t != UINT) {
+ /* illegal bit-field type */
+ error(35);
+ sz = tp->t_flen;
+ dsym->s_type = tp = duptyp(gettyp(t = INT));
+ if ((tp->t_flen = sz) > size(t))
+ tp->t_flen = size(t);
+ }
+ if ((len = tp->t_flen) < 0 || len > size(t)) {
+ /* illegal bit-field size */
+ error(36);
+ tp->t_flen = size(t);
+ } else if (len == 0 && dsym->s_name != unnamed) {
+ /* zero size bit-field */
+ error(37);
+ tp->t_flen = size(t);
+ }
+ if (dsym->s_scl == MOU) {
+ /* illegal use of bit-field */
+ error(41);
+ dsym->s_type->t_isfield = 0;
+ dsym->s_field = 0;
+ }
+ } else if (t == FUNC) {
+ /* function illegal in structure or union */
+ error(38);
+ dsym->s_type = tp = incref(tp, t = PTR);
+ }
+
+ /*
+ * bit-fields of length 0 are not warned about because length()
+ * does not return the length of the bit-field but the length
+ * of the type the bit-field is packed in (its ok)
+ */
+ if ((sz = length(dsym->s_type, dsym->s_name)) == 0) {
+ if (t == ARRAY && dsym->s_type->t_dim == 0) {
+ /* illegal zero sized structure member: %s */
+ warning(39, dsym->s_name);
+ }
+ }
+
+ if (dcs->d_ctx == MOU) {
+ o = dcs->d_offset;
+ dcs->d_offset = 0;
+ }
+ if (dsym->s_field) {
+ align(getbound(tp), tp->t_flen);
+ dsym->s_value.v_quad = (dcs->d_offset / size(t)) * size(t);
+ tp->t_foffs = dcs->d_offset - (int)dsym->s_value.v_quad;
+ dcs->d_offset += tp->t_flen;
+ } else {
+ align(getbound(tp), 0);
+ dsym->s_value.v_quad = dcs->d_offset;
+ dcs->d_offset += sz;
+ }
+ if (dcs->d_ctx == MOU) {
+ if (o > dcs->d_offset)
+ dcs->d_offset = o;
+ }
+
+ chkfdef(dsym, 0);
+
+ return (dsym);
+}
+
+/*
+ * Aligns next structure element as required.
+ *
+ * al contains the required alignment, len the length of a bit-field.
+ */
+static void
+align(al, len)
+ int al, len;
+{
+ int no;
+
+ /*
+ * The alignment of the current element becomes the alignment of
+ * the struct/union if it is larger than the current alignment
+ * of the struct/union.
+ */
+ if (al > dcs->d_stralign)
+ dcs->d_stralign = al;
+
+ no = (dcs->d_offset + (al - 1)) & ~(al - 1);
+ if (len == 0 || dcs->d_offset + len > no)
+ dcs->d_offset = no;
+}
+
+/*
+ * Remember the width of the field in its type structure.
+ */
+sym_t *
+bitfield(dsym, len)
+ sym_t *dsym;
+ int len;
+{
+ if (dsym == NULL) {
+ dsym = getblk(sizeof (sym_t));
+ dsym->s_name = unnamed;
+ dsym->s_kind = FMOS;
+ dsym->s_scl = MOS;
+ dsym->s_type = gettyp(INT);
+ dsym->s_blklev = -1;
+ }
+ dsym->s_type = duptyp(dsym->s_type);
+ dsym->s_type->t_isfield = 1;
+ dsym->s_type->t_flen = len;
+ dsym->s_field = 1;
+ return (dsym);
+}
+
+/*
+ * Collect informations about a sequence of asterisks and qualifiers
+ * in a list of type pqinf_t.
+ * Qualifiers refer always to the left asterisk. The rightmost asterisk
+ * will be at the top of the list.
+ */
+pqinf_t *
+mergepq(p1, p2)
+ pqinf_t *p1, *p2;
+{
+ pqinf_t *p;
+
+ if (p2->p_pcnt != 0) {
+ /* left '*' at the end of the list */
+ for (p = p2; p->p_nxt != NULL; p = p->p_nxt) ;
+ p->p_nxt = p1;
+ return (p2);
+ } else {
+ if (p2->p_const) {
+ if (p1->p_const) {
+ /* duplicate %s */
+ warning(10, "const");
+ }
+ p1->p_const = 1;
+ }
+ if (p2->p_volatile) {
+ if (p1->p_volatile) {
+ /* duplicate %s */
+ warning(10, "volatile");
+ }
+ p1->p_volatile = 1;
+ }
+ free(p2);
+ return (p1);
+ }
+}
+
+/*
+ * Followint 3 functions extend the type of a declarator with
+ * pointer, function and array types.
+ *
+ * The current type is the Type built by deftyp() (dcs->d_type) and
+ * pointer, function and array types already added for this
+ * declarator. The new type extension is inserted between both.
+ */
+sym_t *
+addptr(decl, pi)
+ sym_t *decl;
+ pqinf_t *pi;
+{
+ type_t **tpp, *tp;
+ pqinf_t *npi;
+
+ tpp = &decl->s_type;
+ while (*tpp != dcs->d_type)
+ tpp = &(*tpp)->t_subt;
+
+ while (pi != NULL) {
+ *tpp = tp = getblk(sizeof (type_t));
+ tp->t_tspec = PTR;
+ tp->t_const = pi->p_const;
+ tp->t_volatile = pi->p_volatile;
+ *(tpp = &tp->t_subt) = dcs->d_type;
+ npi = pi->p_nxt;
+ free(pi);
+ pi = npi;
+ }
+ return (decl);
+}
+
+/*
+ * If a dimension was specified, dim is 1, otherwise 0
+ * n is the specified dimension
+ */
+sym_t *
+addarray(decl, dim, n)
+ sym_t *decl;
+ int dim, n;
+{
+ type_t **tpp, *tp;
+
+ tpp = &decl->s_type;
+ while (*tpp != dcs->d_type)
+ tpp = &(*tpp)->t_subt;
+
+ *tpp = tp = getblk(sizeof (type_t));
+ tp->t_tspec = ARRAY;
+ tp->t_subt = dcs->d_type;
+ tp->t_dim = n;
+
+ if (n < 0) {
+ /* zero or negative array dimension */
+ error(20);
+ n = 0;
+ } else if (n == 0 && dim) {
+ /* zero or negative array dimension */
+ warning(20);
+ } else if (n == 0 && !dim) {
+ /* is incomplete type */
+ setcompl(tp, 1);
+ }
+
+ return (decl);
+}
+
+sym_t *
+addfunc(decl, args)
+ sym_t *decl, *args;
+{
+ type_t **tpp, *tp;
+
+ if (dcs->d_proto) {
+ if (tflag)
+ /* function prototypes are illegal in traditional C */
+ warning(270);
+ args = nsfunc(decl, args);
+ } else {
+ osfunc(decl, args);
+ }
+
+ /*
+ * The symbols are removed from the symbol table by popdecl() after
+ * addfunc(). To be able to restore them if this is a function
+ * definition, a pointer to the list of all symbols is stored in
+ * dcs->d_nxt->d_fpsyms. Also a list of the arguments (concatenated
+ * by s_nxt) is stored in dcs->d_nxt->d_fargs.
+ * (dcs->d_nxt must be used because *dcs is the declaration stack
+ * element created for the list of params and is removed after
+ * addfunc())
+ */
+ if (dcs->d_nxt->d_ctx == EXTERN &&
+ decl->s_type == dcs->d_nxt->d_type) {
+ dcs->d_nxt->d_fpsyms = dcs->d_dlsyms;
+ dcs->d_nxt->d_fargs = args;
+ }
+
+ tpp = &decl->s_type;
+ while (*tpp != dcs->d_nxt->d_type)
+ tpp = &(*tpp)->t_subt;
+
+ *tpp = tp = getblk(sizeof (type_t));
+ tp->t_tspec = FUNC;
+ tp->t_subt = dcs->d_nxt->d_type;
+ if ((tp->t_proto = dcs->d_proto) != 0)
+ tp->t_args = args;
+ tp->t_vararg = dcs->d_vararg;
+
+ return (decl);
+}
+
+/*
+ * Called for new style function declarations.
+ */
+/* ARGSUSED */
+static sym_t *
+nsfunc(decl, args)
+ sym_t *decl, *args;
+{
+ sym_t *arg, *sym;
+ scl_t sc;
+ int n;
+
+ /*
+ * Declarations of structs/unions/enums in param lists are legal,
+ * but senseless.
+ */
+ for (sym = dcs->d_dlsyms; sym != NULL; sym = sym->s_dlnxt) {
+ sc = sym->s_scl;
+ if (sc == STRTAG || sc == UNIONTAG || sc == ENUMTAG) {
+ /* dubious tag declaration: %s %s */
+ warning(85, scltoa(sc), sym->s_name);
+ }
+ }
+
+ n = 1;
+ for (arg = args; arg != NULL; arg = arg->s_nxt) {
+ if (arg->s_type->t_tspec == VOID) {
+ if (n > 1 || arg->s_nxt != NULL) {
+ /* "void" must be sole parameter */
+ error(60);
+ arg->s_type = gettyp(INT);
+ }
+ }
+ n++;
+ }
+
+ /* return NULL if first param is VOID */
+ return (args != NULL && args->s_type->t_tspec != VOID ? args : NULL);
+}
+
+/*
+ * Called for old style function declarations.
+ */
+static void
+osfunc(decl, args)
+ sym_t *decl, *args;
+{
+ /*
+ * Remember list of params only if this is really seams to be
+ * a function definition.
+ */
+ if (dcs->d_nxt->d_ctx == EXTERN &&
+ decl->s_type == dcs->d_nxt->d_type) {
+ /*
+ * We assume that this becomes a function definition. If
+ * we are wrong, its corrected in chkfdef().
+ */
+ if (args != NULL) {
+ decl->s_osdef = 1;
+ decl->s_args = args;
+ }
+ } else {
+ if (args != NULL)
+ /* function prototype parameters must have types */
+ warning(62);
+ }
+}
+
+/*
+ * Lists of Identifiers in functions declarations are allowed only if
+ * its also a function definition. If this is not the case, print a
+ * error message.
+ */
+void
+chkfdef(sym, msg)
+ sym_t *sym;
+ int msg;
+{
+ if (sym->s_osdef) {
+ if (msg) {
+ /* incomplete or misplaced function definition */
+ error(22);
+ }
+ sym->s_osdef = 0;
+ sym->s_args = NULL;
+ }
+}
+
+/*
+ * Process the name in a declarator.
+ * If the symbol does already exists, a new one is created.
+ * The symbol becomes one of the storage classes EXTERN, STATIC, AUTO or
+ * TYPEDEF.
+ * s_def and s_reg are valid after dname().
+ */
+sym_t *
+dname(sym)
+ sym_t *sym;
+{
+ scl_t sc;
+
+ if (sym->s_scl == NOSCL) {
+ dcs->d_rdcsym = NULL;
+ } else if (sym->s_defarg) {
+ sym->s_defarg = 0;
+ dcs->d_rdcsym = NULL;
+ } else {
+ dcs->d_rdcsym = sym;
+ sym = pushdown(sym);
+ }
+
+ switch (dcs->d_ctx) {
+ case MOS:
+ case MOU:
+ /* Parent setzen */
+ sym->s_styp = dcs->d_tagtyp->t_str;
+ sym->s_def = DEF;
+ sym->s_value.v_tspec = INT;
+ sc = dcs->d_ctx;
+ break;
+ case EXTERN:
+ /*
+ * static and external symbols without "extern" are
+ * considered to be tentative defined, external
+ * symbols with "extern" are declared, and typedef names
+ * are defined. Tentative defined and declared symbols
+ * may become defined if an initializer is present or
+ * this is a function definition.
+ */
+ if ((sc = dcs->d_scl) == NOSCL) {
+ sc = EXTERN;
+ sym->s_def = TDEF;
+ } else if (sc == STATIC) {
+ sym->s_def = TDEF;
+ } else if (sc == TYPEDEF) {
+ sym->s_def = DEF;
+ } else if (sc == EXTERN) {
+ sym->s_def = DECL;
+ } else {
+ lerror("dname() 1");
+ }
+ break;
+ case PARG:
+ sym->s_arg = 1;
+ /* FALLTHROUGH */
+ case ARG:
+ if ((sc = dcs->d_scl) == NOSCL) {
+ sc = AUTO;
+ } else if (sc == REG) {
+ sym->s_reg = 1;
+ sc = AUTO;
+ } else {
+ lerror("dname() 2");
+ }
+ sym->s_def = DEF;
+ break;
+ case AUTO:
+ if ((sc = dcs->d_scl) == NOSCL) {
+ /*
+ * XXX somewhat ugly because we dont know whether
+ * this is AUTO or EXTERN (functions). If we are
+ * wrong it must be corrected in decl1loc(), where
+ * we have the neccessary type information.
+ */
+ sc = AUTO;
+ sym->s_def = DEF;
+ } else if (sc == AUTO || sc == STATIC || sc == TYPEDEF) {
+ sym->s_def = DEF;
+ } else if (sc == REG) {
+ sym->s_reg = 1;
+ sc = AUTO;
+ sym->s_def = DEF;
+ } else if (sc == EXTERN) {
+ sym->s_def = DECL;
+ } else {
+ lerror("dname() 3");
+ }
+ break;
+ default:
+ lerror("dname() 4");
+ }
+ sym->s_scl = sc;
+
+ sym->s_type = dcs->d_type;
+
+ dcs->d_fpsyms = NULL;
+
+ return (sym);
+}
+
+/*
+ * Process a name in the list of formal params in an old style function
+ * definition.
+ */
+sym_t *
+iname(sym)
+ sym_t *sym;
+{
+ if (sym->s_scl != NOSCL) {
+ if (blklev == sym->s_blklev) {
+ /* redeclaration of formal parameter %s */
+ error(21, sym->s_name);
+ if (!sym->s_defarg)
+ lerror("iname()");
+ }
+ sym = pushdown(sym);
+ }
+ sym->s_type = gettyp(INT);
+ sym->s_scl = AUTO;
+ sym->s_def = DEF;
+ sym->s_defarg = sym->s_arg = 1;
+ return (sym);
+}
+
+/*
+ * Create the type of a tag.
+ *
+ * tag points to the symbol table entry of the tag
+ * kind is the kind of the tag (STRUCT/UNION/ENUM)
+ * decl is 1 if the type of the tag will be completed in this declaration
+ * (the following token is T_LBRACE)
+ * semi is 1 if the following token is T_SEMI
+ */
+type_t *
+mktag(tag, kind, decl, semi)
+ sym_t *tag;
+ tspec_t kind;
+ int decl, semi;
+{
+ scl_t scl;
+ type_t *tp;
+
+ if (kind == STRUCT) {
+ scl = STRTAG;
+ } else if (kind == UNION) {
+ scl = UNIONTAG;
+ } else if (kind == ENUM) {
+ scl = ENUMTAG;
+ } else {
+ lerror("mktag()");
+ }
+
+ if (tag != NULL) {
+ if (tag->s_scl != NOSCL) {
+ tag = newtag(tag, scl, decl, semi);
+ } else {
+ /* a new tag, no empty declaration */
+ dcs->d_nxt->d_nedecl = 1;
+ if (scl == ENUMTAG && !decl) {
+ if (!tflag && (sflag || pflag))
+ /* forward reference to enum type */
+ warning(42);
+ }
+ }
+ if (tag->s_scl == NOSCL) {
+ tag->s_scl = scl;
+ tag->s_type = tp = getblk(sizeof (type_t));
+ } else {
+ tp = tag->s_type;
+ }
+ } else {
+ tag = getblk(sizeof (sym_t));
+ tag->s_name = unnamed;
+ STRUCT_ASSIGN(tag->s_dpos, curr_pos);
+ tag->s_kind = FTAG;
+ tag->s_scl = scl;
+ tag->s_blklev = -1;
+ tag->s_type = tp = getblk(sizeof (type_t));
+ dcs->d_nxt->d_nedecl = 1;
+ }
+
+ if (tp->t_tspec == NOTSPEC) {
+ tp->t_tspec = kind;
+ if (kind != ENUM) {
+ tp->t_str = getblk(sizeof (str_t));
+ tp->t_str->align = CHAR_BIT;
+ tp->t_str->stag = tag;
+ } else {
+ tp->t_isenum = 1;
+ tp->t_enum = getblk(sizeof (enum_t));
+ tp->t_enum->etag = tag;
+ }
+ /* ist unvollstaendiger Typ */
+ setcompl(tp, 1);
+ }
+
+ return (tp);
+}
+
+/*
+ * Checks all possible cases of tag redeclarations.
+ * decl is 1 if T_LBRACE follows
+ * semi is 1 if T_SEMI follows
+ */
+static sym_t *
+newtag(tag, scl, decl, semi)
+ sym_t *tag;
+ scl_t scl;
+ int decl, semi;
+{
+ if (tag->s_blklev < blklev) {
+ if (semi) {
+ /* "struct a;" */
+ if (!tflag) {
+ if (!sflag)
+ /* decl. introduces new type ... */
+ warning(44, scltoa(scl), tag->s_name);
+ tag = pushdown(tag);
+ } else if (tag->s_scl != scl) {
+ /* base type is really "%s %s" */
+ warning(45, scltoa(tag->s_scl), tag->s_name);
+ }
+ dcs->d_nxt->d_nedecl = 1;
+ } else if (decl) {
+ /* "struct a { ..." */
+ if (hflag)
+ /* redefinition hides earlier one: %s */
+ warning(43, tag->s_name);
+ tag = pushdown(tag);
+ dcs->d_nxt->d_nedecl = 1;
+ } else if (tag->s_scl != scl) {
+ /* base type is really "%s %s" */
+ warning(45, scltoa(tag->s_scl), tag->s_name);
+ /* declaration introduces new type in ANSI C: %s %s */
+ if (!sflag)
+ warning(44, scltoa(scl), tag->s_name);
+ tag = pushdown(tag);
+ dcs->d_nxt->d_nedecl = 1;
+ }
+ } else {
+ if (tag->s_scl != scl) {
+ /* (%s) tag redeclared */
+ error(46, scltoa(tag->s_scl));
+ prevdecl(-1, tag);
+ tag = pushdown(tag);
+ dcs->d_nxt->d_nedecl = 1;
+ } else if (decl && !incompl(tag->s_type)) {
+ /* (%s) tag redeclared */
+ error(46, scltoa(tag->s_scl));
+ prevdecl(-1, tag);
+ tag = pushdown(tag);
+ dcs->d_nxt->d_nedecl = 1;
+ } else if (semi || decl) {
+ dcs->d_nxt->d_nedecl = 1;
+ }
+ }
+ return (tag);
+}
+
+const char *
+scltoa(sc)
+ scl_t sc;
+{
+ const char *s;
+
+ switch (sc) {
+ case EXTERN: s = "extern"; break;
+ case STATIC: s = "static"; break;
+ case AUTO: s = "auto"; break;
+ case REG: s = "register"; break;
+ case TYPEDEF: s = "typedef"; break;
+ case STRTAG: s = "struct"; break;
+ case UNIONTAG: s = "union"; break;
+ case ENUMTAG: s = "enum"; break;
+ default: lerror("tagttoa()");
+ }
+ return (s);
+}
+
+/*
+ * Completes the type of a tag in a struct/union/enum declaration.
+ * tp points to the type of the, tag, fmem to the list of members/enums.
+ */
+type_t *
+compltag(tp, fmem)
+ type_t *tp;
+ sym_t *fmem;
+{
+ tspec_t t;
+ str_t *sp;
+ int n;
+ sym_t *mem;
+
+ /* from now a complete type */
+ setcompl(tp, 0);
+
+ if ((t = tp->t_tspec) != ENUM) {
+ align(dcs->d_stralign, 0);
+ sp = tp->t_str;
+ sp->align = dcs->d_stralign;
+ sp->size = dcs->d_offset;
+ sp->memb = fmem;
+ if (sp->size == 0) {
+ /* zero sized %s */
+ (void)gnuism(47, ttab[t].tt_name);
+ } else {
+ n = 0;
+ for (mem = fmem; mem != NULL; mem = mem->s_nxt) {
+ if (mem->s_name != unnamed)
+ n++;
+ }
+ if (n == 0) {
+ /* %s has no named members */
+ warning(65,
+ t == STRUCT ? "structure" : "union");
+ }
+ }
+ } else {
+ tp->t_enum->elem = fmem;
+ }
+ return (tp);
+}
+
+/*
+ * Processes the name of an enumerator in en enum declaration.
+ *
+ * sym points to the enumerator
+ * val is the value of the enumerator
+ * impl is 1 if the the value of the enumerator was not explicit specified.
+ */
+sym_t *
+ename(sym, val, impl)
+ sym_t *sym;
+ int val, impl;
+{
+ if (sym->s_scl) {
+ if (sym->s_blklev == blklev) {
+ /* no hflag, because this is illegal!!! */
+ if (sym->s_arg) {
+ /* enumeration constant hides parameter: %s */
+ warning(57, sym->s_name);
+ } else {
+ /* redeclaration of %s */
+ error(27, sym->s_name);
+ /*
+ * inside blocks it should not too complicated
+ * to find the position of the previous
+ * declaration
+ */
+ if (blklev == 0)
+ prevdecl(-1, sym);
+ }
+ } else {
+ if (hflag)
+ /* redefinition hides earlier one: %s */
+ warning(43, sym->s_name);
+ }
+ sym = pushdown(sym);
+ }
+ sym->s_scl = ENUMCON;
+ sym->s_type = dcs->d_tagtyp;
+ sym->s_value.v_tspec = INT;
+ sym->s_value.v_quad = val;
+ if (impl && val - 1 == INT_MAX) {
+ /* overflow in enumeration values: %s */
+ warning(48, sym->s_name);
+ }
+ enumval = val + 1;
+ return (sym);
+}
+
+/*
+ * Process a single external declarator.
+ */
+void
+decl1ext(dsym, initflg)
+ sym_t *dsym;
+ int initflg;
+{
+ int warn, rval, redec;
+ sym_t *rdsym;
+
+ chkfdef(dsym, 1);
+
+ chktyp(dsym);
+
+ if (initflg && !(initerr = chkinit(dsym)))
+ dsym->s_def = DEF;
+
+ /*
+ * Declarations of functions are marked as "tentative" in dname().
+ * This is wrong because there are no tentative function
+ * definitions.
+ */
+ if (dsym->s_type->t_tspec == FUNC && dsym->s_def == TDEF)
+ dsym->s_def = DECL;
+
+ if (dcs->d_inline) {
+ if (dsym->s_type->t_tspec == FUNC) {
+ dsym->s_inline = 1;
+ } else {
+ /* variable declared inline: %s */
+ warning(268, dsym->s_name);
+ }
+ }
+
+ /* Write the declaration into the output file */
+ if (plibflg && llibflg &&
+ dsym->s_type->t_tspec == FUNC && dsym->s_type->t_proto) {
+ /*
+ * With both LINTLIBRARY and PROTOLIB the prototyp is
+ * written as a function definition to the output file.
+ */
+ rval = dsym->s_type->t_subt->t_tspec != VOID;
+ outfdef(dsym, &dsym->s_dpos, rval, 0, NULL);
+ } else {
+ outsym(dsym, dsym->s_scl, dsym->s_def);
+ }
+
+ if ((rdsym = dcs->d_rdcsym) != NULL) {
+
+ /*
+ * If the old symbol stems from a old style function definition
+ * we have remembered the params in rdsmy->s_args and compare
+ * them with the params of the prototype.
+ */
+ if (rdsym->s_osdef && dsym->s_type->t_proto) {
+ redec = chkosdef(rdsym, dsym);
+ } else {
+ redec = 0;
+ }
+
+ if (!redec && !isredec(dsym, (warn = 0, &warn))) {
+
+ if (warn) {
+ /* redeclaration of %s */
+ (*(sflag ? error : warning))(27, dsym->s_name);
+ prevdecl(-1, rdsym);
+ }
+
+ /*
+ * Overtake the rememberd params if the new symbol
+ * is not a prototype.
+ */
+ if (rdsym->s_osdef && !dsym->s_type->t_proto) {
+ dsym->s_osdef = rdsym->s_osdef;
+ dsym->s_args = rdsym->s_args;
+ STRUCT_ASSIGN(dsym->s_dpos, rdsym->s_dpos);
+ }
+
+ /*
+ * Remember the position of the declaration if the
+ * old symbol was a prototype and the new is not.
+ * Also remember the position if the old symbol
+ * was defined and the new is not.
+ */
+ if (rdsym->s_type->t_proto && !dsym->s_type->t_proto) {
+ STRUCT_ASSIGN(dsym->s_dpos, rdsym->s_dpos);
+ } else if (rdsym->s_def == DEF && dsym->s_def != DEF) {
+ STRUCT_ASSIGN(dsym->s_dpos, rdsym->s_dpos);
+ }
+
+ /*
+ * Copy informations about usage of the name into
+ * the new symbol.
+ */
+ cpuinfo(dsym, rdsym);
+
+ /* Once a name is defined, it remains defined. */
+ if (rdsym->s_def == DEF)
+ dsym->s_def = DEF;
+
+ /* once a function is inline, it remains inline */
+ if (rdsym->s_inline)
+ dsym->s_inline = 1;
+
+ compltyp(dsym, rdsym);
+
+ }
+
+ rmsym(rdsym);
+ }
+
+ if (dsym->s_scl == TYPEDEF) {
+ dsym->s_type = duptyp(dsym->s_type);
+ dsym->s_type->t_typedef = 1;
+ settdsym(dsym->s_type, dsym);
+ }
+
+}
+
+/*
+ * Copies informations about usage into a new symbol table entry of
+ * the same symbol.
+ */
+void
+cpuinfo(sym, rdsym)
+ sym_t *sym, *rdsym;
+{
+ sym->s_spos = rdsym->s_spos;
+ sym->s_upos = rdsym->s_upos;
+ sym->s_set = rdsym->s_set;
+ sym->s_used = rdsym->s_used;
+}
+
+/*
+ * Prints an error and returns 1 if a symbol is redeclared/redefined.
+ * Otherwise returns 0 and, in some cases of minor problems, prints
+ * a warning.
+ */
+int
+isredec(dsym, warn)
+ sym_t *dsym;
+ int *warn;
+{
+ sym_t *rsym;
+
+ if ((rsym = dcs->d_rdcsym)->s_scl == ENUMCON) {
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ prevdecl(-1, rsym);
+ return (1);
+ }
+ if (rsym->s_scl == TYPEDEF) {
+ /* typedef redeclared: %s */
+ error(89, dsym->s_name);
+ prevdecl(-1, rsym);
+ return (1);
+ }
+ if (dsym->s_scl == TYPEDEF) {
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ prevdecl(-1, rsym);
+ return (1);
+ }
+ if (rsym->s_def == DEF && dsym->s_def == DEF) {
+ /* redefinition of %s */
+ error(28, dsym->s_name);
+ prevdecl(-1, rsym);
+ return(1);
+ }
+ if (!eqtype(rsym->s_type, dsym->s_type, 0, 0, warn)) {
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ prevdecl(-1, rsym);
+ return(1);
+ }
+ if (rsym->s_scl == EXTERN && dsym->s_scl == EXTERN)
+ return(0);
+ if (rsym->s_scl == STATIC && dsym->s_scl == STATIC)
+ return(0);
+ if (rsym->s_scl == STATIC && dsym->s_def == DECL)
+ return(0);
+ if (rsym->s_scl == EXTERN && rsym->s_def == DEF) {
+ /*
+ * All cases except "int a = 1; static int a;" are catched
+ * above with or without a warning
+ */
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ prevdecl(-1, rsym);
+ return(1);
+ }
+ if (rsym->s_scl == EXTERN) {
+ /* previously declared extern, becomes static: %s */
+ warning(29, dsym->s_name);
+ prevdecl(-1, rsym);
+ return(0);
+ }
+ /*
+ * Now its on of:
+ * "static a; int a;", "static a; int a = 1;", "static a = 1; int a;"
+ */
+ /* redeclaration of %s; ANSI C requires "static" */
+ if (sflag) {
+ warning(30, dsym->s_name);
+ prevdecl(-1, rsym);
+ }
+ dsym->s_scl = STATIC;
+ return (0);
+}
+
+/*
+ * Checks if two types are compatible. Returns 0 if not, otherwise 1.
+ *
+ * ignqual ignore qualifiers of type; used for function params
+ * promot promote left type; used for comparision of params of
+ * old style function definitions with params of prototypes.
+ * *warn set to 1 if an old style function declaration is not
+ * compatible with a prototype
+ */
+int
+eqtype(tp1, tp2, ignqual, promot, warn)
+ type_t *tp1, *tp2;
+ int ignqual, promot, *warn;
+{
+ tspec_t t;
+
+ while (tp1 != NULL && tp2 != NULL) {
+
+ t = tp1->t_tspec;
+ if (promot) {
+ if (t == FLOAT) {
+ t = DOUBLE;
+ } else if (t == CHAR || t == SCHAR) {
+ t = INT;
+ } else if (t == UCHAR) {
+ t = tflag ? UINT : INT;
+ } else if (t == SHORT) {
+ t = INT;
+ } else if (t == USHORT) {
+ /* CONSTCOND */
+ t = INT_MAX < USHRT_MAX || tflag ? UINT : INT;
+ }
+ }
+
+ if (t != tp2->t_tspec)
+ return (0);
+
+ if (tp1->t_const != tp2->t_const && !ignqual && !tflag)
+ return (0);
+
+ if (tp1->t_volatile != tp2->t_volatile && !ignqual && !tflag)
+ return (0);
+
+ if (t == STRUCT || t == UNION)
+ return (tp1->t_str == tp2->t_str);
+
+ if (t == ARRAY && tp1->t_dim != tp2->t_dim) {
+ if (tp1->t_dim != 0 && tp2->t_dim != 0)
+ return (0);
+ }
+
+ /* dont check prototypes for traditional */
+ if (t == FUNC && !tflag) {
+ if (tp1->t_proto && tp2->t_proto) {
+ if (!eqargs(tp1, tp2, warn))
+ return (0);
+ } else if (tp1->t_proto) {
+ if (!mnoarg(tp1, warn))
+ return (0);
+ } else if (tp2->t_proto) {
+ if (!mnoarg(tp2, warn))
+ return (0);
+ }
+ }
+
+ tp1 = tp1->t_subt;
+ tp2 = tp2->t_subt;
+ ignqual = promot = 0;
+
+ }
+
+ return (tp1 == tp2);
+}
+
+/*
+ * Compares the parameter types of two prototypes.
+ */
+static int
+eqargs(tp1, tp2, warn)
+ type_t *tp1, *tp2;
+ int *warn;
+{
+ sym_t *a1, *a2;
+
+ if (tp1->t_vararg != tp2->t_vararg)
+ return (0);
+
+ a1 = tp1->t_args;
+ a2 = tp2->t_args;
+
+ while (a1 != NULL && a2 != NULL) {
+
+ if (eqtype(a1->s_type, a2->s_type, 1, 0, warn) == 0)
+ return (0);
+
+ a1 = a1->s_nxt;
+ a2 = a2->s_nxt;
+
+ }
+
+ return (a1 == a2);
+}
+
+/*
+ * mnoarg() (matches functions with no argument type information)
+ * returns 1 if all parameters of a prototype are compatible with
+ * and old style function declaration.
+ * This is the case if following conditions are met:
+ * 1. the prototype must have a fixed number of parameters
+ * 2. no parameter is of type float
+ * 3. no parameter is converted to another type if integer promotion
+ * is applied on it
+ */
+static int
+mnoarg(tp, warn)
+ type_t *tp;
+ int *warn;
+{
+ sym_t *arg;
+ tspec_t t;
+
+ if (tp->t_vararg) {
+ if (warn != NULL)
+ *warn = 1;
+ }
+ for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt) {
+ if ((t = arg->s_type->t_tspec) == FLOAT ||
+ t == CHAR || t == SCHAR || t == UCHAR ||
+ t == SHORT || t == USHORT) {
+ if (warn != NULL)
+ *warn = 1;
+ }
+ }
+ return (1);
+}
+
+/*
+ * Compares a prototype declaration with the remembered arguments of
+ * a previous old style function definition.
+ */
+static int
+chkosdef(rdsym, dsym)
+ sym_t *rdsym, *dsym;
+{
+ sym_t *args, *pargs, *arg, *parg;
+ int narg, nparg, n;
+ int warn, msg;
+
+ args = rdsym->s_args;
+ pargs = dsym->s_type->t_args;
+
+ msg = 0;
+
+ narg = nparg = 0;
+ for (arg = args; arg != NULL; arg = arg->s_nxt)
+ narg++;
+ for (parg = pargs; parg != NULL; parg = parg->s_nxt)
+ nparg++;
+ if (narg != nparg) {
+ /* prototype does not match old-style definition */
+ error(63);
+ msg = 1;
+ goto end;
+ }
+
+ arg = args;
+ parg = pargs;
+ n = 1;
+ while (narg--) {
+ warn = 0;
+ /*
+ * If it does not match due to promotion and sflag is
+ * not set we print only a warning.
+ */
+ if (!eqtype(arg->s_type, parg->s_type, 1, 1, &warn) || warn) {
+ /* prototype does not match old-style def., arg #%d */
+ error(299, n);
+ msg = 1;
+ }
+ arg = arg->s_nxt;
+ parg = parg->s_nxt;
+ n++;
+ }
+
+ end:
+ if (msg)
+ /* old style definition */
+ prevdecl(300, rdsym);
+
+ return (msg);
+}
+
+/*
+ * Complets a type by copying the dimension and prototype information
+ * from a second compatible type.
+ *
+ * Following lines are legal:
+ * "typedef a[]; a b; a b[10]; a c; a c[20];"
+ * "typedef ft(); ft f; f(int); ft g; g(long);"
+ * This means that, if a type is completed, the type structure must
+ * be duplicated.
+ */
+void
+compltyp(dsym, ssym)
+ sym_t *dsym, *ssym;
+{
+ type_t **dstp, *src;
+ type_t *dst;
+
+ dstp = &dsym->s_type;
+ src = ssym->s_type;
+
+ while ((dst = *dstp) != NULL) {
+ if (src == NULL || dst->t_tspec != src->t_tspec)
+ lerror("compltyp() 1");
+ if (dst->t_tspec == ARRAY) {
+ if (dst->t_dim == 0 && src->t_dim != 0) {
+ *dstp = dst = duptyp(dst);
+ dst->t_dim = src->t_dim;
+ /* now a complete Typ */
+ setcompl(dst, 0);
+ }
+ } else if (dst->t_tspec == FUNC) {
+ if (!dst->t_proto && src->t_proto) {
+ *dstp = dst = duptyp(dst);
+ dst->t_proto = 1;
+ dst->t_args = src->t_args;
+ }
+ }
+ dstp = &dst->t_subt;
+ src = src->t_subt;
+ }
+}
+
+/*
+ * Completes the declaration of a single argument.
+ */
+sym_t *
+decl1arg(sym, initflg)
+ sym_t *sym;
+ int initflg;
+{
+ tspec_t t;
+
+ chkfdef(sym, 1);
+
+ chktyp(sym);
+
+ if (dcs->d_rdcsym != NULL && dcs->d_rdcsym->s_blklev == blklev) {
+ /* redeclaration of formal parameter %s */
+ error(237, sym->s_name);
+ rmsym(dcs->d_rdcsym);
+ sym->s_arg = 1;
+ }
+
+ if (!sym->s_arg) {
+ /* declared argument %s is missing */
+ error(53, sym->s_name);
+ sym->s_arg = 1;
+ }
+
+ if (initflg) {
+ /* cannot initialize parameter: %s */
+ error(52, sym->s_name);
+ initerr = 1;
+ }
+
+ if ((t = sym->s_type->t_tspec) == ARRAY) {
+ sym->s_type = incref(sym->s_type->t_subt, PTR);
+ } else if (t == FUNC) {
+ if (tflag)
+ /* a function is declared as an argument: %s */
+ warning(50, sym->s_name);
+ sym->s_type = incref(sym->s_type, PTR);
+ } else if (t == FLOAT) {
+ if (tflag)
+ sym->s_type = gettyp(DOUBLE);
+ }
+
+ if (dcs->d_inline)
+ /* argument declared inline: %s */
+ warning(269, sym->s_name);
+
+ /*
+ * Arguments must have complete types. lengths() prints the needed
+ * error messages (null dimension is impossible because arrays are
+ * converted to pointers).
+ */
+ if (sym->s_type->t_tspec != VOID)
+ (void)length(sym->s_type, sym->s_name);
+
+ setsflg(sym);
+
+ return (sym);
+}
+
+/*
+ * Does some checks for lint directives which apply to functions.
+ * Processes arguments in old style function definitions which default
+ * to int.
+ * Checks compatiblility of old style function definition with previous
+ * prototype.
+ */
+void
+cluparg()
+{
+ sym_t *args, *arg, *pargs, *parg;
+ int narg, nparg, n, msg;
+ tspec_t t;
+
+ args = funcsym->s_args;
+ pargs = funcsym->s_type->t_args;
+
+ /* check for illegal combinations of lint directives */
+ if (prflstrg != -1 && scflstrg != -1) {
+ /* can't be used together: ** PRINTFLIKE ** ** SCANFLIKE ** */
+ warning(289);
+ prflstrg = scflstrg = -1;
+ }
+ if (nvararg != -1 && (prflstrg != -1 || scflstrg != -1)) {
+ /* dubious use of ** VARARGS ** with ** %s ** */
+ warning(288, prflstrg != -1 ? "PRINTFLIKE" : "SCANFLIKE");
+ nvararg = -1;
+ }
+
+ /*
+ * check if the argument of a lint directive is compatible with the
+ * number of arguments.
+ */
+ narg = 0;
+ for (arg = dcs->d_fargs; arg != NULL; arg = arg->s_nxt)
+ narg++;
+ if (nargusg > narg) {
+ /* argument number mismatch with directive: ** %s ** */
+ warning(283, "ARGSUSED");
+ nargusg = 0;
+ }
+ if (nvararg > narg) {
+ /* argument number mismatch with directive: ** %s ** */
+ warning(283, "VARARGS");
+ nvararg = 0;
+ }
+ if (prflstrg > narg) {
+ /* argument number mismatch with directive: ** %s ** */
+ warning(283, "PRINTFLIKE");
+ prflstrg = -1;
+ } else if (prflstrg == 0) {
+ prflstrg = -1;
+ }
+ if (scflstrg > narg) {
+ /* argument number mismatch with directive: ** %s ** */
+ warning(283, "SCANFLIKE");
+ scflstrg = -1;
+ } else if (scflstrg == 0) {
+ scflstrg = -1;
+ }
+ if (prflstrg != -1 || scflstrg != -1) {
+ narg = prflstrg != -1 ? prflstrg : scflstrg;
+ arg = dcs->d_fargs;
+ for (n = 1; n < narg; n++)
+ arg = arg->s_nxt;
+ if (arg->s_type->t_tspec != PTR ||
+ ((t = arg->s_type->t_subt->t_tspec) != CHAR &&
+ t != UCHAR && t != SCHAR)) {
+ /* arg. %d must be 'char *' for PRINTFLIKE/SCANFLIKE */
+ warning(293, narg);
+ prflstrg = scflstrg = -1;
+ }
+ }
+
+ /*
+ * print a warning for each argument off an old style function
+ * definition which defaults to int
+ */
+ for (arg = args; arg != NULL; arg = arg->s_nxt) {
+ if (arg->s_defarg) {
+ /* argument type defaults to int: %s */
+ warning(32, arg->s_name);
+ arg->s_defarg = 0;
+ setsflg(arg);
+ }
+ }
+
+ /*
+ * If this is an old style function definition and a prototyp
+ * exists, compare the types of arguments.
+ */
+ if (funcsym->s_osdef && funcsym->s_type->t_proto) {
+ /*
+ * If the number of arguments does not macht, we need not
+ * continue.
+ */
+ narg = nparg = 0;
+ msg = 0;
+ for (parg = pargs; parg != NULL; parg = parg->s_nxt)
+ nparg++;
+ for (arg = args; arg != NULL; arg = arg->s_nxt)
+ narg++;
+ if (narg != nparg) {
+ /* parameter mismatch: %d declared, %d defined */
+ error(51, nparg, narg);
+ msg = 1;
+ } else {
+ parg = pargs;
+ arg = args;
+ while (narg--) {
+ msg |= chkptdecl(arg, parg);
+ parg = parg->s_nxt;
+ arg = arg->s_nxt;
+ }
+ }
+ if (msg)
+ /* prototype declaration */
+ prevdecl(285, dcs->d_rdcsym);
+
+ /* from now the prototype is valid */
+ funcsym->s_osdef = 0;
+ funcsym->s_args = NULL;
+
+ }
+
+}
+
+/*
+ * Checks compatibility of an old style function definition with a previous
+ * prototype declaration.
+ * Returns 1 if the position of the previous declaration should be reported.
+ */
+static int
+chkptdecl(arg, parg)
+ sym_t *arg, *parg;
+{
+ type_t *tp, *ptp;
+ int warn, msg;
+
+ tp = arg->s_type;
+ ptp = parg->s_type;
+
+ msg = 0;
+ warn = 0;
+
+ if (!eqtype(tp, ptp, 1, 1, &warn)) {
+ if (eqtype(tp, ptp, 1, 0, &warn)) {
+ /* type does not match prototype: %s */
+ msg = gnuism(58, arg->s_name);
+ } else {
+ /* type does not match prototype: %s */
+ error(58, arg->s_name);
+ msg = 1;
+ }
+ } else if (warn) {
+ /* type does not match prototype: %s */
+ (*(sflag ? error : warning))(58, arg->s_name);
+ msg = 1;
+ }
+
+ return (msg);
+}
+
+/*
+ * Completes a single local declaration/definition.
+ */
+void
+decl1loc(dsym, initflg)
+ sym_t *dsym;
+ int initflg;
+{
+ /* Correct a mistake done in dname(). */
+ if (dsym->s_type->t_tspec == FUNC) {
+ dsym->s_def = DECL;
+ if (dcs->d_scl == NOSCL)
+ dsym->s_scl = EXTERN;
+ }
+
+ if (dsym->s_type->t_tspec == FUNC) {
+ if (dsym->s_scl == STATIC) {
+ /* dubious static function at block level: %s */
+ warning(93, dsym->s_name);
+ dsym->s_scl = EXTERN;
+ } else if (dsym->s_scl != EXTERN && dsym->s_scl != TYPEDEF) {
+ /* function has illegal storage class: %s */
+ error(94, dsym->s_name);
+ dsym->s_scl = EXTERN;
+ }
+ }
+
+ /*
+ * functions may be declared inline at local scope, although
+ * this has no effect for a later definition of the same
+ * function.
+ * XXX it should have an effect if tflag is set. this would
+ * also be the way gcc behaves.
+ */
+ if (dcs->d_inline) {
+ if (dsym->s_type->t_tspec == FUNC) {
+ dsym->s_inline = 1;
+ } else {
+ /* variable declared inline: %s */
+ warning(268, dsym->s_name);
+ }
+ }
+
+ chkfdef(dsym, 1);
+
+ chktyp(dsym);
+
+ if (dcs->d_rdcsym != NULL && dsym->s_scl == EXTERN)
+ ledecl(dsym);
+
+ if (dsym->s_scl == EXTERN) {
+ /*
+ * XXX wenn die statische Variable auf Ebene 0 erst
+ * spaeter definiert wird, haben wir die Brille auf.
+ */
+ if (dsym->s_xsym == NULL) {
+ outsym(dsym, EXTERN, dsym->s_def);
+ } else {
+ outsym(dsym, dsym->s_xsym->s_scl, dsym->s_def);
+ }
+ }
+
+ if (dcs->d_rdcsym != NULL) {
+
+ if (dcs->d_rdcsym->s_blklev == 0) {
+
+ switch (dsym->s_scl) {
+ case AUTO:
+ /* automatic hides external declaration: %s */
+ if (hflag)
+ warning(86, dsym->s_name);
+ break;
+ case STATIC:
+ /* static hides external declaration: %s */
+ if (hflag)
+ warning(87, dsym->s_name);
+ break;
+ case TYPEDEF:
+ /* typedef hides external declaration: %s */
+ if (hflag)
+ warning(88, dsym->s_name);
+ break;
+ case EXTERN:
+ /*
+ * Warnings and errors are printed in ledecl()
+ */
+ break;
+ default:
+ lerror("decl1loc() 1");
+ }
+
+ } else if (dcs->d_rdcsym->s_blklev == blklev) {
+
+ /* no hflag, because its illegal! */
+ if (dcs->d_rdcsym->s_arg) {
+ /*
+ * if !tflag, a "redeclaration of %s" error
+ * is produced below
+ */
+ if (tflag) {
+ if (hflag)
+ /* decl. hides parameter: %s */
+ warning(91, dsym->s_name);
+ rmsym(dcs->d_rdcsym);
+ }
+ }
+
+ } else if (dcs->d_rdcsym->s_blklev < blklev) {
+
+ if (hflag)
+ /* declaration hides earlier one: %s */
+ warning(95, dsym->s_name);
+
+ }
+
+ if (dcs->d_rdcsym->s_blklev == blklev) {
+
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ rmsym(dcs->d_rdcsym);
+
+ }
+
+ }
+
+ if (initflg && !(initerr = chkinit(dsym))) {
+ dsym->s_def = DEF;
+ setsflg(dsym);
+ }
+
+ if (dsym->s_scl == TYPEDEF) {
+ dsym->s_type = duptyp(dsym->s_type);
+ dsym->s_type->t_typedef = 1;
+ settdsym(dsym->s_type, dsym);
+ }
+
+ /*
+ * Before we can check the size we must wait for a initialisation
+ * which may follow.
+ */
+}
+
+/*
+ * Processes (re)declarations of external Symbols inside blocks.
+ */
+static void
+ledecl(dsym)
+ sym_t *dsym;
+{
+ int eqt, warn;
+ sym_t *esym;
+
+ /* look for a symbol with the same name */
+ esym = dcs->d_rdcsym;
+ while (esym != NULL && esym->s_blklev != 0) {
+ while ((esym = esym->s_link) != NULL) {
+ if (esym->s_kind != FVFT)
+ continue;
+ if (strcmp(dsym->s_name, esym->s_name) == 0)
+ break;
+ }
+ }
+ if (esym == NULL)
+ return;
+ if (esym->s_scl != EXTERN && esym->s_scl != STATIC) {
+ /* gcc accepts this without a warning, pcc prints an error. */
+ /* redeclaration of %s */
+ warning(27, dsym->s_name);
+ prevdecl(-1, esym);
+ return;
+ }
+
+ warn = 0;
+ eqt = eqtype(esym->s_type, dsym->s_type, 0, 0, &warn);
+
+ if (!eqt || warn) {
+ if (esym->s_scl == EXTERN) {
+ /* inconsistent redeclaration of extern: %s */
+ warning(90, dsym->s_name);
+ prevdecl(-1, esym);
+ } else {
+ /* inconsistent redeclaration of static: %s */
+ warning(92, dsym->s_name);
+ prevdecl(-1, esym);
+ }
+ }
+
+ if (eqt) {
+ /*
+ * Remember the external symbol so we can update usage
+ * information at the end of the block.
+ */
+ dsym->s_xsym = esym;
+ }
+}
+
+/*
+ * Print an error or a warning if the symbol cant be initialized due
+ * to type/storage class. Returnvalue is 1 if an error has been
+ * detected.
+ */
+static int
+chkinit(sym)
+ sym_t *sym;
+{
+ int err;
+
+ err = 0;
+
+ if (sym->s_type->t_tspec == FUNC) {
+ /* cannot initialize function: %s */
+ error(24, sym->s_name);
+ err = 1;
+ } else if (sym->s_scl == TYPEDEF) {
+ /* cannot initialize typedef: %s */
+ error(25, sym->s_name);
+ err = 1;
+ } else if (sym->s_scl == EXTERN && sym->s_def == DECL) {
+ /* cannot initialize "extern" declaration: %s */
+ if (dcs->d_ctx == EXTERN) {
+ warning(26, sym->s_name);
+ } else {
+ error(26, sym->s_name);
+ err = 1;
+ }
+ }
+
+ return (err);
+}
+
+/*
+ * Create a symbole for an abstract declaration.
+ */
+sym_t *
+aname()
+{
+ sym_t *sym;
+
+ if (dcs->d_ctx != ABSTRACT && dcs->d_ctx != PARG)
+ lerror("aname()");
+
+ sym = getblk(sizeof (sym_t));
+
+ sym->s_name = unnamed;
+ sym->s_def = DEF;
+ sym->s_scl = ABSTRACT;
+ sym->s_blklev = -1;
+
+ if (dcs->d_ctx == PARG)
+ sym->s_arg = 1;
+
+ sym->s_type = dcs->d_type;
+ dcs->d_rdcsym = NULL;
+ dcs->d_vararg = 0;
+
+ return (sym);
+}
+
+/*
+ * Removes anything which has nothing to do on global level.
+ */
+void
+globclup()
+{
+ while (dcs->d_nxt != NULL)
+ popdecl();
+
+ cleanup();
+ blklev = 0;
+ mblklev = 0;
+
+ /*
+ * remove all informations about pending lint directives without
+ * warnings.
+ */
+ glclup(1);
+}
+
+/*
+ * Process an abstract type declaration
+ */
+sym_t *
+decl1abs(sym)
+ sym_t *sym;
+{
+ chkfdef(sym, 1);
+ chktyp(sym);
+ return (sym);
+}
+
+/*
+ * Checks size after declarations of variables and their initialisation.
+ */
+void
+chksz(dsym)
+ sym_t *dsym;
+{
+ /*
+ * check size only for symbols which are defined and no function and
+ * not typedef name
+ */
+ if (dsym->s_def != DEF)
+ return;
+ if (dsym->s_scl == TYPEDEF)
+ return;
+ if (dsym->s_type->t_tspec == FUNC)
+ return;
+
+ if (length(dsym->s_type, dsym->s_name) == 0 &&
+ dsym->s_type->t_tspec == ARRAY && dsym->s_type->t_dim == 0) {
+ /* empty array declaration: %s */
+ if (tflag) {
+ warning(190, dsym->s_name);
+ } else {
+ error(190, dsym->s_name);
+ }
+ }
+}
+
+/*
+ * Mark an object as set if it is not already
+ */
+void
+setsflg(sym)
+ sym_t *sym;
+{
+ if (!sym->s_set) {
+ sym->s_set = 1;
+ STRUCT_ASSIGN(sym->s_spos, curr_pos);
+ }
+}
+
+/*
+ * Mark an object as used if it is not already
+ */
+void
+setuflg(sym, fcall, szof)
+ sym_t *sym;
+ int fcall, szof;
+{
+ if (!sym->s_used) {
+ sym->s_used = 1;
+ STRUCT_ASSIGN(sym->s_upos, curr_pos);
+ }
+ /*
+ * for function calls another record is written
+ *
+ * XXX Should symbols used in sizeof() treated as used or not?
+ * Probably not, because there is no sense to declare an
+ * external variable only to get their size.
+ */
+ if (!fcall && !szof && sym->s_kind == FVFT && sym->s_scl == EXTERN)
+ outusg(sym);
+}
+
+/*
+ * Prints warnings for a list of variables and labels (concatenated
+ * with s_dlnxt) if these are not used or only set.
+ */
+void
+chkusage(di)
+ dinfo_t *di;
+{
+ sym_t *sym;
+ int mknowarn;
+
+ /* for this warnings LINTED has no effect */
+ mknowarn = nowarn;
+ nowarn = 0;
+
+ for (sym = di->d_dlsyms; sym != NULL; sym = sym->s_dlnxt)
+ chkusg1(di->d_asm, sym);
+
+ nowarn = mknowarn;
+}
+
+/*
+ * Prints a warning for a single variable or label if it is not used or
+ * only set.
+ */
+void
+chkusg1(novar, sym)
+ int novar;
+ sym_t *sym;
+{
+ pos_t cpos;
+
+ if (sym->s_blklev == -1)
+ return;
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+
+ if (sym->s_kind == FVFT) {
+ if (sym->s_arg) {
+ chkausg(novar, sym);
+ } else {
+ chkvusg(novar, sym);
+ }
+ } else if (sym->s_kind == FLAB) {
+ chklusg(sym);
+ } else if (sym->s_kind == FTAG) {
+ chktusg(sym);
+ }
+
+ STRUCT_ASSIGN(curr_pos, cpos);
+}
+
+static void
+chkausg(novar, arg)
+ int novar;
+ sym_t *arg;
+{
+ if (!arg->s_set)
+ lerror("chkausg() 1");
+
+ if (novar)
+ return;
+
+ if (!arg->s_used && vflag) {
+ STRUCT_ASSIGN(curr_pos, arg->s_dpos);
+ /* argument %s unused in function %s */
+ warning(231, arg->s_name, funcsym->s_name);
+ }
+}
+
+static void
+chkvusg(novar, sym)
+ int novar;
+ sym_t *sym;
+{
+ scl_t sc;
+ sym_t *xsym;
+
+ if (blklev == 0 || sym->s_blklev == 0)
+ lerror("chkvusg() 1");
+
+ /* errors in expressions easily cause lots of these warnings */
+ if (nerr != 0)
+ return;
+
+ /*
+ * XXX Only variables are checkd, although types should
+ * probably also be checked
+ */
+ if ((sc = sym->s_scl) != EXTERN && sc != STATIC &&
+ sc != AUTO && sc != REG) {
+ return;
+ }
+
+ if (novar)
+ return;
+
+ if (sc == EXTERN) {
+ if (!sym->s_used && !sym->s_set) {
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ /* %s unused in function %s */
+ warning(192, sym->s_name, funcsym->s_name);
+ }
+ } else {
+ if (sym->s_set && !sym->s_used) {
+ STRUCT_ASSIGN(curr_pos, sym->s_spos);
+ /* %s set but not used in function %s */
+ warning(191, sym->s_name, funcsym->s_name);
+ } else if (!sym->s_used) {
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ /* %s unused in function %s */
+ warning(192, sym->s_name, funcsym->s_name);
+ }
+ }
+
+ if (sc == EXTERN) {
+ /*
+ * information about usage is taken over into the symbol
+ * tabel entry at level 0 if the symbol was locally declared
+ * as an external symbol.
+ *
+ * XXX This is wrong for symbols declared static at level 0
+ * if the usage information stems from sizeof(). This is
+ * because symbols at level 0 only used in sizeof() are
+ * considered to not be used.
+ */
+ if ((xsym = sym->s_xsym) != NULL) {
+ if (sym->s_used && !xsym->s_used) {
+ xsym->s_used = 1;
+ STRUCT_ASSIGN(xsym->s_upos, sym->s_upos);
+ }
+ if (sym->s_set && !xsym->s_set) {
+ xsym->s_set = 1;
+ STRUCT_ASSIGN(xsym->s_spos, sym->s_spos);
+ }
+ }
+ }
+}
+
+static void
+chklusg(lab)
+ sym_t *lab;
+{
+ if (blklev != 1 || lab->s_blklev != 1)
+ lerror("chklusg() 1");
+
+ if (lab->s_set && !lab->s_used) {
+ STRUCT_ASSIGN(curr_pos, lab->s_spos);
+ /* label %s unused in function %s */
+ warning(192, lab->s_name, funcsym->s_name);
+ } else if (!lab->s_set) {
+ STRUCT_ASSIGN(curr_pos, lab->s_upos);
+ /* undefined label %s */
+ warning(23, lab->s_name);
+ }
+}
+
+static void
+chktusg(sym)
+ sym_t *sym;
+{
+ if (!incompl(sym->s_type))
+ return;
+
+ /* complain alwasy about incomplet tags declared inside blocks */
+ if (!zflag || dcs->d_ctx != EXTERN)
+ return;
+
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ switch (sym->s_type->t_tspec) {
+ case STRUCT:
+ /* struct %s never defined */
+ warning(233, sym->s_name);
+ break;
+ case UNION:
+ /* union %s never defined */
+ warning(234, sym->s_name);
+ break;
+ case ENUM:
+ /* enum %s never defined */
+ warning(235, sym->s_name);
+ break;
+ default:
+ lerror("chktusg() 1");
+ }
+}
+
+/*
+ * Called after the entire translation unit has been parsed.
+ * Changes tentative definitions in definitions.
+ * Performs some tests on global Symbols. Detected Problems are:
+ * - defined variables of incomplete type
+ * - constant variables which are not initialized
+ * - static symbols which are never used
+ */
+void
+chkglsyms()
+{
+ sym_t *sym;
+ pos_t cpos;
+
+ if (blklev != 0 || dcs->d_nxt != NULL)
+ norecover();
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+
+ for (sym = dcs->d_dlsyms; sym != NULL; sym = sym->s_dlnxt) {
+ if (sym->s_blklev == -1)
+ continue;
+ if (sym->s_kind == FVFT) {
+ chkglvar(sym);
+ } else if (sym->s_kind == FTAG) {
+ chktusg(sym);
+ } else {
+ if (sym->s_kind != FMOS)
+ lerror("chkglsyms() 1");
+ }
+ }
+
+ STRUCT_ASSIGN(curr_pos, cpos);
+}
+
+static void
+chkglvar(sym)
+ sym_t *sym;
+{
+ if (sym->s_scl == TYPEDEF || sym->s_scl == ENUMCON)
+ return;
+
+ if (sym->s_scl != EXTERN && sym->s_scl != STATIC)
+ lerror("chkglvar() 1");
+
+ glchksz(sym);
+
+ if (sym->s_scl == STATIC) {
+ if (sym->s_type->t_tspec == FUNC) {
+ if (sym->s_used && sym->s_def != DEF) {
+ STRUCT_ASSIGN(curr_pos, sym->s_upos);
+ /* static func. called but not def.. */
+ error(225, sym->s_name);
+ }
+ }
+ if (!sym->s_used) {
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ if (sym->s_type->t_tspec == FUNC) {
+ if (sym->s_def == DEF) {
+ if (!sym->s_inline)
+ /* static function %s unused */
+ warning(236, sym->s_name);
+ } else {
+ /* static function %s decl. but ... */
+ warning(290, sym->s_name);
+ }
+ } else if (!sym->s_set) {
+ /* static variable %s unused */
+ warning(226, sym->s_name);
+ } else {
+ /* static variable %s set but not used */
+ warning(307, sym->s_name);
+ }
+ }
+ if (!tflag && sym->s_def == TDEF && sym->s_type->t_const) {
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ /* const object %s should have initializer */
+ warning(227, sym->s_name);
+ }
+ }
+}
+
+static void
+glchksz(sym)
+ sym_t *sym;
+{
+ if (sym->s_def == TDEF) {
+ if (sym->s_type->t_tspec == FUNC)
+ /*
+ * this can happen if an syntax error occured
+ * after a function declaration
+ */
+ return;
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ if (length(sym->s_type, sym->s_name) == 0 &&
+ sym->s_type->t_tspec == ARRAY && sym->s_type->t_dim == 0) {
+ /* empty array declaration: %s */
+ if (tflag || (sym->s_scl == EXTERN && !sflag)) {
+ warning(190, sym->s_name);
+ } else {
+ error(190, sym->s_name);
+ }
+ }
+ }
+}
+
+/*
+ * Prints information about location of previous definition/declaration.
+ */
+void
+prevdecl(msg, psym)
+ int msg;
+ sym_t *psym;
+{
+ pos_t cpos;
+
+ if (!rflag)
+ return;
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+ STRUCT_ASSIGN(curr_pos, psym->s_dpos);
+ if (msg != -1) {
+ message(msg, psym->s_name);
+ } else if (psym->s_def == DEF || psym->s_def == TDEF) {
+ /* previous definition of %s */
+ message(261, psym->s_name);
+ } else {
+ /* previous declaration of %s */
+ message(260, psym->s_name);
+ }
+ STRUCT_ASSIGN(curr_pos, cpos);
+}
diff --git a/usr.bin/xlint/lint1/emit.c b/usr.bin/xlint/lint1/emit.c
new file mode 100644
index 0000000..f98f540
--- /dev/null
+++ b/usr.bin/xlint/lint1/emit.c
@@ -0,0 +1,241 @@
+/* $NetBSD: emit.c,v 1.2 1995/07/03 21:24:00 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: emit.c,v 1.2 1995/07/03 21:24:00 cgd Exp $";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <err.h>
+
+#include "lint.h"
+
+/* name and handle of output file */
+static const char *loname;
+static FILE *lout;
+
+/* output buffer data */
+ob_t ob;
+
+static void outxbuf __P((void));
+
+
+/*
+ * initialize output
+ */
+void
+outopen(name)
+ const char *name;
+{
+ loname = name;
+
+ /* Ausgabedatei oeffnen */
+ if ((lout = fopen(name, "w")) == NULL)
+ err(1, "cannot open '%s'", name);
+
+ /* Ausgabepuffer anlegen */
+ ob.o_len = 1024;
+ ob.o_end = (ob.o_buf = ob.o_nxt = xmalloc(ob.o_len)) + ob.o_len;
+}
+
+/*
+ * flush output buffer and close file
+ */
+void
+outclose()
+{
+ outclr();
+ if (fclose(lout) == EOF)
+ err(1, "cannot close '%s'", loname);
+}
+
+/*
+ * resize output buffer
+ */
+static void
+outxbuf()
+{
+ ptrdiff_t coffs;
+
+ coffs = ob.o_nxt - ob.o_buf;
+ ob.o_len *= 2;
+ ob.o_end = (ob.o_buf = xrealloc(ob.o_buf, ob.o_len)) + ob.o_len;
+ ob.o_nxt = ob.o_buf + coffs;
+}
+
+/*
+ * reset output buffer
+ * if it is not empty, it is flushed
+ */
+void
+outclr()
+{
+ size_t sz;
+
+ if (ob.o_buf != ob.o_nxt) {
+ outchar('\n');
+ sz = ob.o_nxt - ob.o_buf;
+ if (sz > ob.o_len)
+ errx(1, "internal error: outclr() 1");
+ if (fwrite(ob.o_buf, sz, 1, lout) != 1)
+ err(1, "cannot write to %s", loname);
+ ob.o_nxt = ob.o_buf;
+ }
+}
+
+/*
+ * write a character to the output buffer
+ */
+void
+outchar(c)
+ int c;
+{
+ if (ob.o_nxt == ob.o_end)
+ outxbuf();
+ *ob.o_nxt++ = (char)c;
+}
+
+/*
+ * write a character to the output buffer, qouted if necessary
+ */
+void
+outqchar(c)
+ int c;
+{
+ if (isprint(c) && c != '\\' && c != '"' && c != '\'') {
+ outchar(c);
+ } else {
+ outchar('\\');
+ switch (c) {
+ case '\\':
+ outchar('\\');
+ break;
+ case '"':
+ outchar('"');
+ break;
+ case '\'':
+ outchar('\'');
+ break;
+ case '\b':
+ outchar('b');
+ break;
+ case '\t':
+ outchar('t');
+ break;
+ case '\n':
+ outchar('n');
+ break;
+ case '\f':
+ outchar('f');
+ break;
+ case '\r':
+ outchar('r');
+ break;
+#ifdef __STDC__
+ case '\v':
+#else
+ case '\013':
+#endif
+ outchar('v');
+ break;
+#ifdef __STDC__
+ case '\a':
+#else
+ case '\007':
+#endif
+ outchar('a');
+ break;
+ default:
+ outchar((((u_int)c >> 6) & 07) + '0');
+ outchar((((u_int)c >> 3) & 07) + '0');
+ outchar((c & 07) + '0');
+ break;
+ }
+ }
+}
+
+/*
+ * write a strint to the output buffer
+ * the string must not contain any characters which
+ * should be quoted
+ */
+void
+outstrg(s)
+ const char *s;
+{
+ while (*s != '\0') {
+ if (ob.o_nxt == ob.o_end)
+ outxbuf();
+ *ob.o_nxt++ = *s++;
+ }
+}
+
+/*
+ * write an integer value to toe output buffer
+ */
+void
+outint(i)
+ int i;
+{
+ if ((ob.o_end - ob.o_nxt) < 3 * sizeof (int))
+ outxbuf();
+ ob.o_nxt += sprintf(ob.o_nxt, "%d", i);
+}
+
+/*
+ * write the name of a symbol to the output buffer
+ * the name is preceeded by its length
+ */
+void
+outname(name)
+ const char *name;
+{
+ if (name == NULL)
+ errx(1, "internal error: outname() 1");
+ outint((int)strlen(name));
+ outstrg(name);
+}
+
+/*
+ * write the name of the .c source
+ */
+void
+outsrc(name)
+ const char *name;
+{
+ outclr();
+ outchar('S');
+ outstrg(name);
+}
diff --git a/usr.bin/xlint/lint1/emit1.c b/usr.bin/xlint/lint1/emit1.c
new file mode 100644
index 0000000..ee2434e
--- /dev/null
+++ b/usr.bin/xlint/lint1/emit1.c
@@ -0,0 +1,587 @@
+/* $NetBSD: emit1.c,v 1.4 1995/10/02 17:21:28 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: emit1.c,v 1.4 1995/10/02 17:21:28 jpo Exp $";
+#endif
+
+#include <ctype.h>
+
+#include "lint1.h"
+
+static void outtt __P((sym_t *, sym_t *));
+static void outfstrg __P((strg_t *));
+
+/*
+ * Write type into the output buffer.
+ * The type is written as a sequence of substrings, each of which describes a
+ * node of type type_t
+ * a node is coded as follows:
+ * char C
+ * signed char s C
+ * unsigned char u C
+ * short S
+ * unsigned short u S
+ * int I
+ * unsigned int u I
+ * long L
+ * unsigned long u L
+ * long long Q
+ * unsigned long long u Q
+ * float s D
+ * double D
+ * long double l D
+ * void V
+ * * P
+ * [n] A n
+ * () F
+ * (void) F 0
+ * (n arguments) F n arg1 arg2 ... argn
+ * (n arguments, ...) F n arg1 arg2 ... argn-1 E
+ * (a, b, c, ...) f n arg1 arg2 ...
+ * enum tag e T tag_or_typename
+ * struct tag s T tag_or_typename
+ * union tag u T tag_or_typename
+ *
+ * tag_or_typename 0 no tag or type name
+ * 1 n tag Tag
+ * 2 n typename only type name
+ *
+ * spaces are only for better readability
+ * additionaly it is possible to prepend the characters 'c' (for const)
+ * and 'v' (for volatile)
+ */
+void
+outtype(tp)
+ type_t *tp;
+{
+ int t, s, na;
+ sym_t *arg;
+ tspec_t ts;
+
+ while (tp != NULL) {
+ if ((ts = tp->t_tspec) == INT && tp->t_isenum)
+ ts = ENUM;
+ switch (ts) {
+ case CHAR: t = 'C'; s = '\0'; break;
+ case SCHAR: t = 'C'; s = 's'; break;
+ case UCHAR: t = 'C'; s = 'u'; break;
+ case SHORT: t = 'S'; s = '\0'; break;
+ case USHORT: t = 'S'; s = 'u'; break;
+ case INT: t = 'I'; s = '\0'; break;
+ case UINT: t = 'I'; s = 'u'; break;
+ case LONG: t = 'L'; s = '\0'; break;
+ case ULONG: t = 'L'; s = 'u'; break;
+ case QUAD: t = 'Q'; s = '\0'; break;
+ case UQUAD: t = 'Q'; s = 'u'; break;
+ case FLOAT: t = 'D'; s = 's'; break;
+ case DOUBLE: t = 'D'; s = '\0'; break;
+ case LDOUBLE: t = 'D'; s = 'l'; break;
+ case VOID: t = 'V'; s = '\0'; break;
+ case PTR: t = 'P'; s = '\0'; break;
+ case ARRAY: t = 'A'; s = '\0'; break;
+ case FUNC: t = 'F'; s = '\0'; break;
+ case ENUM: t = 'T'; s = 'e'; break;
+ case STRUCT: t = 'T'; s = 's'; break;
+ case UNION: t = 'T'; s = 'u'; break;
+ default:
+ lerror("outtyp() 1");
+ }
+ if (tp->t_const)
+ outchar('c');
+ if (tp->t_volatile)
+ outchar('v');
+ if (s != '\0')
+ outchar(s);
+ outchar(t);
+ if (ts == ARRAY) {
+ outint(tp->t_dim);
+ } else if (ts == ENUM) {
+ outtt(tp->t_enum->etag, tp->t_enum->etdef);
+ } else if (ts == STRUCT || ts == UNION) {
+ outtt(tp->t_str->stag, tp->t_str->stdef);
+ } else if (ts == FUNC && tp->t_proto) {
+ na = 0;
+ for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
+ na++;
+ if (tp->t_vararg)
+ na++;
+ outint(na);
+ for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
+ outtype(arg->s_type);
+ if (tp->t_vararg)
+ outchar('E');
+ }
+ tp = tp->t_subt;
+ }
+}
+
+/*
+ * type to string
+ * used for debugging output
+ *
+ * it uses its own output buffer for conversion
+ */
+const char *
+ttos(tp)
+ type_t *tp;
+{
+ static ob_t tob;
+ ob_t tmp;
+
+ if (tob.o_buf == NULL) {
+ tob.o_len = 64;
+ tob.o_buf = tob.o_nxt = xmalloc(tob.o_len);
+ tob.o_end = tob.o_buf + tob.o_len;
+ }
+
+ tmp = ob;
+ ob = tob;
+ ob.o_nxt = ob.o_buf;
+ outtype(tp);
+ outchar('\0');
+ tob = ob;
+ ob = tmp;
+
+ return (tob.o_buf);
+}
+
+/*
+ * write the name of a tag or typename
+ *
+ * if the tag is named, the name of the
+ * tag is written, otherwise, if a typename exists which
+ * refers to this tag, this typename is written
+ */
+static void
+outtt(tag, tdef)
+ sym_t *tag, *tdef;
+{
+ if (tag->s_name != unnamed) {
+ outint(1);
+ outname(tag->s_name);
+ } else if (tdef != NULL) {
+ outint(2);
+ outname(tdef->s_name);
+ } else {
+ outint(0);
+ }
+}
+
+/*
+ * write information about an global declared/defined symbol
+ * with storage class extern
+ *
+ * informations about function definitions are written in outfdef(),
+ * not here
+ */
+void
+outsym(sym, sc, def)
+ sym_t *sym;
+ scl_t sc;
+ def_t def;
+{
+ /*
+ * Static function declarations must also be written to the output
+ * file. Compatibility of function declarations (for both static
+ * and extern functions) must be checked in lint2. Lint1 can't do
+ * this, especially not, if functions are declared at block level
+ * before their first declaration at level 0.
+ */
+ if (sc != EXTERN && !(sc == STATIC && sym->s_type->t_tspec == FUNC))
+ return;
+
+ /* reset buffer */
+ outclr();
+
+ /*
+ * line number of .c source, 'd' for declaration, Id of current
+ * source (.c or .h), and line in current source.
+ */
+ outint(csrc_pos.p_line);
+ outchar('d');
+ outint(getfnid(sym->s_dpos.p_file));
+ outchar('.');
+ outint(sym->s_dpos.p_line);
+
+ /* flags */
+
+ switch (def) {
+ case DEF:
+ /* defined */
+ outchar('d');
+ break;
+ case TDEF:
+ /* tentative defined */
+ outchar('t');
+ break;
+ case DECL:
+ /* declared */
+ outchar('e');
+ break;
+ default:
+ lerror("outsym() 2");
+ }
+ if (llibflg && def != DECL) {
+ /*
+ * mark it as used so we get no warnings from lint2 about
+ * unused symbols in libraries.
+ */
+ outchar('u');
+ }
+
+ if (sc == STATIC)
+ outchar('s');
+
+ /* name of the symbol */
+ outname(sym->s_name);
+
+ /* type of the symbol */
+ outtype(sym->s_type);
+}
+
+/*
+ * write information about function definition
+ *
+ * this is also done for static functions so we are able to check if
+ * they are called with proper argument types
+ */
+void
+outfdef(fsym, posp, rval, osdef, args)
+ sym_t *fsym, *args;
+ pos_t *posp;
+ int rval, osdef;
+{
+ int narg;
+ sym_t *arg;
+
+ /* reset the buffer */
+ outclr();
+
+ /*
+ * line number of .c source, 'd' for declaration, Id of current
+ * source (.c or .h), and line in current source
+ *
+ * we are already at the end of the function. If we are in the
+ * .c source, posp->p_line is correct, otherwise csrc_pos.p_line
+ * (for functions defined in header files).
+ */
+ if (posp->p_file == csrc_pos.p_file) {
+ outint(posp->p_line);
+ } else {
+ outint(csrc_pos.p_line);
+ }
+ outchar('d');
+ outint(getfnid(posp->p_file));
+ outchar('.');
+ outint(posp->p_line);
+
+ /* flags */
+
+ /* both SCANFLIKE and PRINTFLIKE imply VARARGS */
+ if (prflstrg != -1) {
+ nvararg = prflstrg;
+ } else if (scflstrg != -1) {
+ nvararg = scflstrg;
+ }
+
+ if (nvararg != -1) {
+ outchar('v');
+ outint(nvararg);
+ }
+ if (scflstrg != -1) {
+ outchar('S');
+ outint(scflstrg);
+ }
+ if (prflstrg != -1) {
+ outchar('P');
+ outint(prflstrg);
+ }
+ nvararg = prflstrg = scflstrg = -1;
+
+ outchar('d');
+
+ if (rval)
+ /* has return value */
+ outchar('r');
+
+ if (llibflg)
+ /*
+ * mark it as used so lint2 does not complain about
+ * unused symbols in libraries
+ */
+ outchar('u');
+
+ if (osdef)
+ /* old style function definition */
+ outchar('o');
+
+ if (fsym->s_scl == STATIC)
+ outchar('s');
+
+ /* name of function */
+ outname(fsym->s_name);
+
+ /* argument types and return value */
+ if (osdef) {
+ narg = 0;
+ for (arg = args; arg != NULL; arg = arg->s_nxt)
+ narg++;
+ outchar('f');
+ outint(narg);
+ for (arg = args; arg != NULL; arg = arg->s_nxt)
+ outtype(arg->s_type);
+ outtype(fsym->s_type->t_subt);
+ } else {
+ outtype(fsym->s_type);
+ }
+}
+
+/*
+ * write out all information necessary for lint2 to check function
+ * calls
+ *
+ * rvused is set if the return value is used (asigned to a variable)
+ * rvdisc is set if the return value is not used and not ignored
+ * (casted to void)
+ */
+void
+outcall(tn, rvused, rvdisc)
+ tnode_t *tn;
+ int rvused, rvdisc;
+{
+ tnode_t *args, *arg;
+ int narg, n, i;
+ quad_t q;
+ tspec_t t;
+
+ /* reset buffer */
+ outclr();
+
+ /*
+ * line number of .c source, 'c' for function call, Id of current
+ * source (.c or .h), and line in current source
+ */
+ outint(csrc_pos.p_line);
+ outchar('c');
+ outint(getfnid(curr_pos.p_file));
+ outchar('.');
+ outint(curr_pos.p_line);
+
+ /*
+ * flags; 'u' and 'i' must be last to make sure a letter
+ * is between the numeric argument of a flag and the name of
+ * the function
+ */
+ narg = 0;
+ args = tn->tn_right;
+ for (arg = args; arg != NULL; arg = arg->tn_right)
+ narg++;
+ /* informations about arguments */
+ for (n = 1; n <= narg; n++) {
+ /* the last argument is the top one in the tree */
+ for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ;
+ arg = arg->tn_left;
+ if (arg->tn_op == CON) {
+ if (isityp(t = arg->tn_type->t_tspec)) {
+ /*
+ * XXX it would probably be better to
+ * explizitly test the sign
+ */
+ if ((q = arg->tn_val->v_quad) == 0) {
+ /* zero constant */
+ outchar('z');
+ } else if (msb(q, t, 0) == 0) {
+ /* positive if casted to signed */
+ outchar('p');
+ } else {
+ /* negative if casted to signed */
+ outchar('n');
+ }
+ outint(n);
+ }
+ } else if (arg->tn_op == AMPER &&
+ arg->tn_left->tn_op == STRING &&
+ arg->tn_left->tn_strg->st_tspec == CHAR) {
+ /* constant string, write all format specifiers */
+ outchar('s');
+ outint(n);
+ outfstrg(arg->tn_left->tn_strg);
+ }
+
+ }
+ /* return value discarded/used/ignored */
+ outchar(rvdisc ? 'd' : (rvused ? 'u' : 'i'));
+
+ /* name of the called function */
+ outname(tn->tn_left->tn_left->tn_sym->s_name);
+
+ /* types of arguments */
+ outchar('f');
+ outint(narg);
+ for (n = 1; n <= narg; n++) {
+ /* the last argument is the top one in the tree */
+ for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ;
+ outtype(arg->tn_left->tn_type);
+ }
+ /* expected type of return value */
+ outtype(tn->tn_type);
+}
+
+/*
+ * extracts potential format specifiers for printf() and scanf() and
+ * writes them, enclosed in "" and qouted if necessary, to the output buffer
+ */
+static void
+outfstrg(strg)
+ strg_t *strg;
+{
+ int c, oc, first;
+ u_char *cp;
+
+ if (strg->st_tspec != CHAR)
+ lerror("outfstrg() 1");
+
+ cp = strg->st_cp;
+
+ outchar('"');
+
+ c = *cp++;
+
+ while (c != '\0') {
+
+ if (c != '%') {
+ c = *cp++;
+ continue;
+ }
+
+ outqchar('%');
+ c = *cp++;
+
+ /* flags for printf and scanf and *-fieldwidth for printf */
+ while (c != '\0' && (c == '-' || c == '+' || c == ' ' ||
+ c == '#' || c == '0' || c == '*')) {
+ outqchar(c);
+ c = *cp++;
+ }
+
+ /* numeric field width */
+ while (c != '\0' && isdigit(c)) {
+ outqchar(c);
+ c = *cp++;
+ }
+
+ /* precision for printf */
+ if (c == '.') {
+ outqchar(c);
+ if ((c = *cp++) == '*') {
+ outqchar(c);
+ c = *cp++;
+ } else {
+ while (c != '\0' && isdigit(c)) {
+ outqchar(c);
+ c = *cp++;
+ }
+ }
+ }
+
+ /* h, l, L and q flags fpr printf and scanf */
+ if (c == 'h' || c == 'l' || c == 'L' || c == 'q') {
+ outqchar(c);
+ c = *cp++;
+ }
+
+ /*
+ * The last character. It is always written so we can detect
+ * invalid format specifiers.
+ */
+ if (c != '\0') {
+ outqchar(c);
+ oc = c;
+ c = *cp++;
+ /*
+ * handle [ for scanf. [-] means that a minus sign
+ * was found at an undefined position.
+ */
+ if (oc == '[') {
+ if (c == '^')
+ c = *cp++;
+ if (c == ']')
+ c = *cp++;
+ first = 1;
+ while (c != '\0' && c != ']') {
+ if (c == '-') {
+ if (!first && *cp != ']')
+ outqchar(c);
+ }
+ first = 0;
+ c = *cp++;
+ }
+ if (c == ']') {
+ outqchar(c);
+ c = *cp++;
+ }
+ }
+ }
+
+ }
+
+ outchar('"');
+}
+
+/*
+ * writes a record if sym was used
+ */
+void
+outusg(sym)
+ sym_t *sym;
+{
+ /* reset buffer */
+ outclr();
+
+ /*
+ * line number of .c source, 'u' for used, Id of current
+ * source (.c or .h), and line in current source
+ */
+ outint(csrc_pos.p_line);
+ outchar('u');
+ outint(getfnid(curr_pos.p_file));
+ outchar('.');
+ outint(curr_pos.p_line);
+
+ /* necessary to delimit both numbers */
+ outchar('x');
+
+ /* Den Namen des Symbols ausgeben */
+ outname(sym->s_name);
+}
diff --git a/usr.bin/xlint/lint1/err.c b/usr.bin/xlint/lint1/err.c
new file mode 100644
index 0000000..32c80c4
--- /dev/null
+++ b/usr.bin/xlint/lint1/err.c
@@ -0,0 +1,543 @@
+/* $NetBSD: err.c,v 1.8 1995/10/02 17:37:00 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: err.c,v 1.8 1995/10/02 17:37:00 jpo Exp $";
+#endif
+
+/* number of errors found */
+int nerr;
+
+/* number of syntax errors */
+int sytxerr;
+
+#include <stdlib.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "lint1.h"
+
+static const char *basename __P((const char *));
+static void verror __P((int, va_list));
+static void vwarning __P((int, va_list));
+
+
+const char *msgs[] = {
+ "syntax error: empty declaration", /* 0 */
+ "old style declaration; add int", /* 1 */
+ "empty declaration", /* 2 */
+ "%s declared in argument declaration list", /* 3 */
+ "illegal type combination", /* 4 */
+ "modifying typedef with '%s'; only qualifiers allowed", /* 5 */
+ "use 'double' instead of 'long float'", /* 6 */
+ "only one storage class allowed", /* 7 */
+ "illegal storage class", /* 8 */
+ "only register valid as formal parameter storage class", /* 9 */
+ "duplicate '%s'", /* 10 */
+ "bit-field initializer out of range", /* 11 */
+ "compiler takes size of function", /* 12 */
+ "incomplete enum type: %s", /* 13 */
+ "compiler takes alignment of function", /* 14 */
+ "function returns illegal type", /* 15 */
+ "array of function is illegal", /* 16 */
+ "null dimension", /* 17 */
+ "illegal use of 'void'", /* 18 */
+ "void type for %s", /* 19 */
+ "zero or negative array dimension", /* 20 */
+ "redeclaration of formal parameter %s", /* 21 */
+ "incomplete or misplaced function definition", /* 22 */
+ "undefined label %s", /* 23 */
+ "cannot initialize function: %s", /* 24 */
+ "cannot initialize typedef: %s", /* 25 */
+ "cannot initialize extern declaration: %s", /* 26 */
+ "redeclaration of %s", /* 27 */
+ "redefinition of %s", /* 28 */
+ "previously declared extern, becomes static: %s", /* 29 */
+ "redeclaration of %s; ANSI C requires static", /* 30 */
+ "incomplete structure or union %s: %s", /* 31 */
+ "argument type defaults to 'int': %s", /* 32 */
+ "duplicate member name: %s", /* 33 */
+ "nonportable bit-field type", /* 34 */
+ "illegal bit-field type", /* 35 */
+ "illegal bit-field size", /* 36 */
+ "zero size bit-field", /* 37 */
+ "function illegal in structure or union", /* 38 */
+ "illegal zero sized structure member: %s", /* 39 */
+ "unknown size: %s", /* 40 */
+ "illegal use of bit-field", /* 41 */
+ "forward reference to enum type", /* 42 */
+ "redefinition hides earlier one: %s", /* 43 */
+ "declaration introduces new type in ANSI C: %s %s", /* 44 */
+ "base type is really '%s %s'", /* 45 */
+ "(%s) tag redeclared", /* 46 */
+ "zero sized %s", /* 47 */
+ "overflow in enumeration values: %s", /* 48 */
+ "struct or union member must be named", /* 49 */
+ "a function is declared as an argument: %s", /* 50 */
+ "parameter mismatch: %d declared, %d defined", /* 51 */
+ "cannot initialize parameter: %s", /* 52 */
+ "declared argument %s is missing", /* 53 */
+ "trailing ',' prohibited in enum declaration", /* 54 */
+ "integral constant expression expected", /* 55 */
+ "integral constant too large", /* 56 */
+ "enumeration constant hides parameter: %s", /* 57 */
+ "type does not match prototype: %s", /* 58 */
+ "formal parameter lacks name: param #%d", /* 59 */
+ "void must be sole parameter", /* 60 */
+ "void parameter cannot have name: %s", /* 61 */
+ "function prototype parameters must have types", /* 62 */
+ "prototype does not match old-style definition", /* 63 */
+ "()-less function definition", /* 64 */
+ "%s has no named members", /* 65 */
+ "syntax requires ';' after last struct/union member", /* 66 */
+ "cannot return incomplete type", /* 67 */
+ "typedef already qualified with '%s'", /* 68 */
+ "inappropriate qualifiers with 'void'", /* 69 */
+ "%soperand of '%s' is unsigned in ANSI C", /* 70 */
+ "too many characters in character constant", /* 71 */
+ "typedef declares no type name", /* 72 */
+ "empty character constant", /* 73 */
+ "no hex digits follow \\x", /* 74 */
+ "overflow in hex escape", /* 75 */
+ "character escape does not fit in character", /* 76 */
+ "bad octal digit %c", /* 77 */
+ "nonportable character escape", /* 78 */
+ "dubious escape \\%c", /* 79 */
+ "dubious escape \\%o", /* 80 */
+ "\\a undefined in traditional C", /* 81 */
+ "\\x undefined in traditional C", /* 82 */
+ "storage class after type is obsolescent", /* 83 */
+ "ANSI C requires formal parameter before '...'", /* 84 */
+ "dubious tag declaration: %s %s", /* 85 */
+ "automatic hides external declaration: %s", /* 86 */
+ "static hides external declaration: %s", /* 87 */
+ "typedef hides external declaration: %s", /* 88 */
+ "typedef redeclared: %s", /* 89 */
+ "inconsistent redeclaration of extern: %s", /* 90 */
+ "declaration hides parameter: %s", /* 91 */
+ "inconsistent redeclaration of static: %s", /* 92 */
+ "dubious static function at block level: %s", /* 93 */
+ "function has illegal storage class: %s", /* 94 */
+ "declaration hides earlier one: %s", /* 95 */
+ "cannot dereference non-pointer type", /* 96 */
+ "suffix U is illegal in traditional C", /* 97 */
+ "suffixes F and L are illegal in traditional C", /* 98 */
+ "%s undefined", /* 99 */
+ "unary + is illegal in traditional C", /* 100 */
+ "undefined struct/union member: %s", /* 101 */
+ "illegal member use: %s", /* 102 */
+ "left operand of '.' must be struct/union object", /* 103 */
+ "left operand of '->' must be pointer to struct/union", /* 104 */
+ "non-unique member requires struct/union %s", /* 105 */
+ "left operand of '->' must be pointer", /* 106 */
+ "operands of '%s' have incompatible types", /* 107 */
+ "operand of '%s' has incompatible type", /* 108 */
+ "void type illegal in expression", /* 109 */
+ "pointer to function is not allowed here", /* 110 */
+ "unacceptable operand of '%s'", /* 111 */
+ "cannot take address of bit-field", /* 112 */
+ "cannot take address of register %s", /* 113 */
+ "%soperand of '%s' must be lvalue", /* 114 */
+ "%soperand of '%s' must be modifiable lvalue", /* 115 */
+ "illegal pointer subtraction", /* 116 */
+ "bitwise operation on signed value possibly nonportable", /* 117 */
+ "semantics of '%s' change in ANSI C; use explicit cast", /* 118 */
+ "conversion of '%s' to '%s' is out of range", /* 119 */
+ "bitwise operation on signed value nonportable", /* 120 */
+ "negative shift", /* 121 */
+ "shift greater than size of object", /* 122 */
+ "illegal combination of pointer and integer, op %s", /* 123 */
+ "illegal pointer combination, op %s", /* 124 */
+ "ANSI C forbids ordered comparisons of pointers to functions",/* 125 */
+ "incompatible types in conditional", /* 126 */
+ "'&' before array or function: ignored", /* 127 */
+ "operands have incompatible pointer types, op %s", /* 128 */
+ "expression has null effect", /* 129 */
+ "enum type mismatch, op %s", /* 130 */
+ "conversion to '%s' may sign-extend incorrectly", /* 131 */
+ "conversion from '%s' may lose accuracy", /* 132 */
+ "conversion of pointer to '%s' loses bits", /* 133 */
+ "conversion of pointer to '%s' may lose bits", /* 134 */
+ "possible pointer alignment problem", /* 135 */
+ "cannot do pointer arithmetic on operand of unknown size", /* 136 */
+ "use of incomplete enum type, op %s", /* 137 */
+ "unknown operand size, op %s", /* 138 */
+ "division by 0", /* 139 */
+ "modulus by 0", /* 140 */
+ "integer overflow detected, op %s", /* 141 */
+ "floating point overflow detected, op %s", /* 142 */
+ "cannot take size of incomplete type", /* 143 */
+ "cannot take size of function", /* 144 */
+ "cannot take size of bit-field", /* 145 */
+ "cannot take size of void", /* 146 */
+ "invalid cast expression", /* 147 */
+ "improper cast of void expression", /* 148 */
+ "illegal function", /* 149 */
+ "argument mismatch: %d arg%s passed, %d expected", /* 150 */
+ "void expressions may not be arguments, arg #%d", /* 151 */
+ "argument cannot have unknown size, arg #%d", /* 152 */
+ "argument has incompatible pointer type, arg #%d", /* 153 */
+ "illegal combination of pointer and integer, arg #%d", /* 154 */
+ "argument is incompatible with prototype, arg #%d", /* 155 */
+ "enum type mismatch, arg #%d", /* 156 */
+ "ANSI C treats constant as unsigned", /* 157 */
+ "%s may be used before set", /* 158 */
+ "assignment in conditional context", /* 159 */
+ "operator '==' found where '=' was expected", /* 160 */
+ "constant in conditional context", /* 161 */
+ "comparision of %s with %s, op %s", /* 162 */
+ "a cast does not yield an lvalue", /* 163 */
+ "assignment of negative constant to unsigned type", /* 164 */
+ "constant truncated by assignment", /* 165 */
+ "precision lost in bit-field assignment", /* 166 */
+ "array subscript cannot be negative: %ld", /* 167 */
+ "array subscript cannot be > %d: %ld", /* 168 */
+ "precedence confusion possible: parenthesize!", /* 169 */
+ "first operand must have scalar type, op ? :", /* 170 */
+ "assignment type mismatch", /* 171 */
+ "too many struct/union initializers", /* 172 */
+ "too many array initializers", /* 173 */
+ "too many initializers", /* 174 */
+ "initialisation of an incomplete type", /* 175 */
+ "invalid initializer", /* 176 */
+ "non-constant initializer", /* 177 */
+ "initializer does not fit", /* 178 */
+ "cannot initialize struct/union with no named member", /* 179 */
+ "bit-field initializer does not fit", /* 180 */
+ "{}-enclosed initializer required", /* 181 */
+ "incompatible pointer types", /* 182 */
+ "illegal combination of pointer and integer", /* 183 */
+ "illegal pointer combination", /* 184 */
+ "initialisation type mismatch", /* 185 */
+ "bit-field initialisation is illegal in traditional C", /* 186 */
+ "non-null byte ignored in string initializer", /* 187 */
+ "no automatic aggregate initialization in traditional C", /* 188 */
+ "assignment of struct/union illegal in traditional C", /* 189 */
+ "empty array declaration: %s", /* 190 */
+ "%s set but not used in function %s", /* 191 */
+ "%s unused in function %s", /* 192 */
+ "statement not reached", /* 193 */
+ "label %s redefined", /* 194 */
+ "case not in switch", /* 195 */
+ "case label affected by conversion", /* 196 */
+ "non-constant case expression", /* 197 */
+ "non-integral case expression", /* 198 */
+ "duplicate case in switch: %ld", /* 199 */
+ "duplicate case in switch: %lu", /* 200 */
+ "default outside switch", /* 201 */
+ "duplicate default in switch", /* 202 */
+ "case label must be of type `int' in traditional C", /* 203 */
+ "controlling expressions must have scalar type", /* 204 */
+ "switch expression must have integral type", /* 205 */
+ "enumeration value(s) not handled in switch", /* 206 */
+ "loop not entered at top", /* 207 */
+ "break outside loop or switch", /* 208 */
+ "continue outside loop", /* 209 */
+ "enum type mismatch in initialisation", /* 210 */
+ "return value type mismatch", /* 211 */
+ "cannot return incomplete type", /* 212 */
+ "void function %s cannot return value", /* 213 */
+ "function %s expects to return value", /* 214 */
+ "function implicitly declared to return int", /* 215 */
+ "function %s has return (e); and return;", /* 216 */
+ "function %s falls off bottom without returning value", /* 217 */
+ "ANSI C treats constant as unsigned, op %s", /* 218 */
+ "concatenated strings are illegal in traditional C", /* 219 */
+ "fallthrough on case statement", /* 220 */
+ "initialisation of unsigned with negative constant", /* 221 */
+ "conversion of negative constant to unsigned type", /* 222 */
+ "end-of-loop code not reached", /* 223 */
+ "cannot recover from previous errors", /* 224 */
+ "static function called but not defined: %s()", /* 225 */
+ "static variable %s unused", /* 226 */
+ "const object %s should have initializer", /* 227 */
+ "function cannot return const or volatile object", /* 228 */
+ "questionable conversion of function pointer", /* 229 */
+ "nonportable character comparision, op %s", /* 230 */
+ "argument %s unused in function %s", /* 231 */
+ "label %s unused in function %s", /* 232 */
+ "struct %s never defined", /* 233 */
+ "union %s never defined", /* 234 */
+ "enum %s never defined", /* 235 */
+ "static function %s unused", /* 236 */
+ "redeclaration of formal parameter %s", /* 237 */
+ "initialisation of union is illegal in traditional C", /* 238 */
+ "constant argument to NOT", /* 239 */
+ "assignment of different structures", /* 240 */
+ "dubious operation on enum, op %s", /* 241 */
+ "combination of '%s' and '%s', op %s", /* 242 */
+ "dubious comparision of enums, op %s", /* 243 */
+ "illegal structure pointer combination", /* 244 */
+ "illegal structure pointer combination, op %s", /* 245 */
+ "dubious conversion of enum to '%s'", /* 246 */
+ "pointer casts may be troublesome", /* 247 */
+ "floating-point constant out of range", /* 248 */
+ "syntax error", /* 249 */
+ "unknown character \\%o", /* 250 */
+ "malformed integer constant", /* 251 */
+ "integer constant out of range", /* 252 */
+ "unterminated character constant", /* 253 */
+ "newline in string or char constant", /* 254 */
+ "undefined or invalid # directive", /* 255 */
+ "unterminated comment", /* 256 */
+ "extra characters in lint comment", /* 257 */
+ "unterminated string constant", /* 258 */
+ "conversion to '%s' due to prototype, arg #%d", /* 259 */
+ "previous declaration of %s", /* 260 */
+ "previous definition of %s", /* 261 */
+ "\\\" inside character constants undefined in traditional C", /* 262 */
+ "\\? undefined in traditional C", /* 263 */
+ "\\v undefined in traditional C", /* 264 */
+ "%s C does not support 'long long'", /* 265 */
+ "'long double' is illegal in traditional C", /* 266 */
+ "shift equal to size of object", /* 267 */
+ "variable declared inline: %s", /* 268 */
+ "argument declared inline: %s", /* 269 */
+ "function prototypes are illegal in traditional C", /* 270 */
+ "switch expression must be of type `int' in traditional C", /* 271 */
+ "empty translation unit", /* 272 */
+ "bit-field type '%s' invalid in ANSI C", /* 273 */
+ "ANSI C forbids comparision of %s with %s", /* 274 */
+ "cast discards 'const' from pointer target type", /* 275 */
+ "", /* 276 */
+ "initialisation of '%s' with '%s'", /* 277 */
+ "combination of '%s' and '%s', arg #%d", /* 278 */
+ "combination of '%s' and '%s' in return", /* 279 */
+ "must be outside function: /* %s */", /* 280 */
+ "duplicate use of /* %s */", /* 281 */
+ "must precede function definition: /* %s */", /* 282 */
+ "argument number mismatch with directive: /* %s */", /* 283 */
+ "fallthrough on default statement", /* 284 */
+ "prototype declaration", /* 285 */
+ "function definition is not a prototype", /* 286 */
+ "function declaration is not a prototype", /* 287 */
+ "dubious use of /* VARARGS */ with /* %s */", /* 288 */
+ "can't be used together: /* PRINTFLIKE */ /* SCANFLIKE */", /* 289 */
+ "static function %s declared but not defined", /* 290 */
+ "invalid multibyte character", /* 291 */
+ "cannot concatenate wide and regular string literals", /* 292 */
+ "argument %d must be 'char *' for PRINTFLIKE/SCANFLIKE", /* 293 */
+ "multi-character character constant", /* 294 */
+ "conversion of '%s' to '%s' is out of range, arg #%d", /* 295 */
+ "conversion of negative constant to unsigned type, arg #%d", /* 296 */
+ "conversion to '%s' may sign-extend incorrectly, arg #%d", /* 297 */
+ "conversion from '%s' may lose accuracy, arg #%d", /* 298 */
+ "prototype does not match old style definition, arg #%d", /* 299 */
+ "old style definition", /* 300 */
+ "array of incomplete type", /* 301 */
+ "%s returns pointer to automatic object", /* 302 */
+ "ANSI C forbids conversion of %s to %s", /* 303 */
+ "ANSI C forbids conversion of %s to %s, arg #%d", /* 304 */
+ "ANSI C forbids conversion of %s to %s, op %s", /* 305 */
+ "constant truncated by conversion, op %s", /* 306 */
+ "static variable %s set but not used", /* 307 */
+ "", /* 308 */
+ "extra bits set to 0 in conversion of '%s' to '%s', op %s", /* 309 */
+};
+
+/*
+ * If Fflag is not set basename() returns a pointer to the last
+ * component of the path, otherwise it returns the argument.
+ */
+static const char *
+basename(path)
+ const char *path;
+{
+ const char *cp, *cp1, *cp2;
+
+ if (Fflag)
+ return (path);
+
+ cp = cp1 = cp2 = path;
+ while (*cp != '\0') {
+ if (*cp++ == '/') {
+ cp2 = cp1;
+ cp1 = cp;
+ }
+ }
+ return (*cp1 == '\0' ? cp2 : cp1);
+}
+
+static void
+verror(n, ap)
+ int n;
+ va_list ap;
+{
+ const char *fn;
+
+ fn = basename(curr_pos.p_file);
+ (void)printf("%s(%d): ", fn, curr_pos.p_line);
+ (void)vprintf(msgs[n], ap);
+ (void)printf("\n");
+ nerr++;
+}
+
+static void
+vwarning(n, ap)
+ int n;
+ va_list ap;
+{
+ const char *fn;
+
+ if (nowarn)
+ /* this warning is suppressed by a LINTED comment */
+ return;
+
+ fn = basename(curr_pos.p_file);
+ (void)printf("%s(%d): warning: ", fn, curr_pos.p_line);
+ (void)vprintf(msgs[n], ap);
+ (void)printf("\n");
+}
+
+void
+#ifdef __STDC__
+error(int n, ...)
+#else
+error(n, va_alist)
+ int n;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+#endif
+ verror(n, ap);
+ va_end(ap);
+}
+
+void
+#ifdef __STDC__
+lerror(const char *msg, ...)
+#else
+lerror(msg, va_alist)
+ const char *msg;
+ va_dcl
+#endif
+{
+ va_list ap;
+ const char *fn;
+
+#ifdef __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+ fn = basename(curr_pos.p_file);
+ (void)fprintf(stderr, "%s(%d): lint error: ", fn, curr_pos.p_line);
+ (void)vfprintf(stderr, msg, ap);
+ (void)fprintf(stderr, "\n");
+ va_end(ap);
+ exit(1);
+}
+
+void
+#ifdef __STDC__
+warning(int n, ...)
+#else
+warning(n, va_alist)
+ int n;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+#endif
+ vwarning(n, ap);
+ va_end(ap);
+}
+
+void
+#ifdef __STDC__
+message(int n, ...)
+#else
+message(n, va_alist)
+ int n;
+ va_dcl
+#endif
+{
+ va_list ap;
+ const char *fn;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+#endif
+ fn = basename(curr_pos.p_file);
+ (void)printf("%s(%d): ", fn, curr_pos.p_line);
+ (void)vprintf(msgs[n], ap);
+ (void)printf("\n");
+ va_end(ap);
+}
+
+int
+#ifdef __STDC__
+gnuism(int n, ...)
+#else
+gnuism(n, va_alist)
+ int n;
+ va_dcl
+#endif
+{
+ va_list ap;
+ int msg;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+#endif
+ if (sflag && !gflag) {
+ verror(n, ap);
+ msg = 1;
+ } else if (!sflag && gflag) {
+ msg = 0;
+ } else {
+ vwarning(n, ap);
+ msg = 1;
+ }
+ va_end(ap);
+
+ return (msg);
+}
diff --git a/usr.bin/xlint/lint1/externs.h b/usr.bin/xlint/lint1/externs.h
new file mode 100644
index 0000000..e61f8d0
--- /dev/null
+++ b/usr.bin/xlint/lint1/externs.h
@@ -0,0 +1,56 @@
+/* $NetBSD: externs.h,v 1.2 1995/07/03 21:24:06 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+/*
+ * mem.c
+ */
+extern void *xmalloc __P((size_t));
+extern void *xcalloc __P((size_t, size_t));
+extern void *xrealloc __P((void *, size_t));
+extern char *xstrdup __P((const char *));
+extern void nomem __P((void));
+
+/*
+ * emit.c
+ */
+extern ob_t ob;
+
+extern void outopen __P((const char *));
+extern void outclose __P((void));
+extern void outclr __P((void));
+extern void outchar __P((int));
+extern void outqchar __P((int));
+extern void outstrg __P((const char *));
+extern void outint __P((int));
+extern void outname __P((const char *));
+extern void outsrc __P((const char *));
diff --git a/usr.bin/xlint/lint1/externs1.h b/usr.bin/xlint/lint1/externs1.h
new file mode 100644
index 0000000..e9923c7
--- /dev/null
+++ b/usr.bin/xlint/lint1/externs1.h
@@ -0,0 +1,281 @@
+/* $NetBSD: externs1.h,v 1.7 1995/10/02 17:31:39 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+/*
+ * main.c
+ */
+extern int aflag;
+extern int bflag;
+extern int cflag;
+extern int dflag;
+extern int eflag;
+extern int Fflag;
+extern int gflag;
+extern int hflag;
+extern int pflag;
+extern int rflag;
+extern int sflag;
+extern int tflag;
+extern int uflag;
+extern int vflag;
+extern int yflag;
+extern int zflag;
+
+extern void norecover __P((void));
+
+/*
+ * cgram.y
+ */
+extern int blklev;
+extern int mblklev;
+extern int yydebug;
+
+extern int yyerror __P((char *));
+extern int yyparse __P((void));
+
+/*
+ * scan.l
+ */
+extern pos_t curr_pos;
+extern pos_t csrc_pos;
+extern symt_t symtyp;
+extern FILE *yyin;
+extern u_quad_t qbmasks[], qlmasks[], qumasks[];
+
+extern void initscan __P((void));
+extern int sign __P((quad_t, tspec_t, int));
+extern int msb __P((quad_t, tspec_t, int));
+extern quad_t xsign __P((quad_t, tspec_t, int));
+extern void clrwflgs __P((void));
+extern sym_t *getsym __P((sbuf_t *));
+extern void cleanup __P((void));
+extern sym_t *pushdown __P((sym_t *));
+extern void rmsym __P((sym_t *));
+extern void rmsyms __P((sym_t *));
+extern void inssym __P((int, sym_t *));
+extern void freeyyv __P((void *, int));
+extern int yylex __P((void));
+
+/*
+ * mem1.c
+ */
+extern const char *fnalloc __P((const char *));
+extern const char *fnnalloc __P((const char *, size_t));
+extern int getfnid __P((const char *));
+
+extern void initmem __P((void));
+
+extern void *getblk __P((size_t));
+extern void *getlblk __P((int, size_t));
+extern void freeblk __P((void));
+extern void freelblk __P((int));
+
+extern void *tgetblk __P((size_t));
+extern tnode_t *getnode __P((void));
+extern void tfreeblk __P((void));
+extern struct mbl *tsave __P((void));
+extern void trestor __P((struct mbl *));
+
+/*
+ * err.c
+ */
+extern int nerr;
+extern int sytxerr;
+extern const char *msgs[];
+
+extern void error __P((int, ...));
+extern void warning __P((int, ...));
+extern void message __P((int, ...));
+extern int gnuism __P((int, ...));
+extern void lerror __P((const char *, ...));
+
+/*
+ * decl.c
+ */
+extern dinfo_t *dcs;
+extern const char *unnamed;
+extern int enumval;
+
+extern void initdecl __P((void));
+extern type_t *gettyp __P((tspec_t));
+extern type_t *duptyp __P((const type_t *));
+extern type_t *tduptyp __P((const type_t *));
+extern int incompl __P((type_t *));
+extern void setcompl __P((type_t *, int));
+extern void addscl __P((scl_t));
+extern void addtype __P((type_t *));
+extern void addqual __P((tqual_t));
+extern void pushdecl __P((scl_t));
+extern void popdecl __P((void));
+extern void setasm __P((void));
+extern void clrtyp __P((void));
+extern void deftyp __P((void));
+extern int length __P((type_t *, const char *));
+extern int getbound __P((type_t *));
+extern sym_t *lnklst __P((sym_t *, sym_t *));
+extern void chktyp __P((sym_t *));
+extern sym_t *decl1str __P((sym_t *));
+extern sym_t *bitfield __P((sym_t *, int));
+extern pqinf_t *mergepq __P((pqinf_t *, pqinf_t *));
+extern sym_t *addptr __P((sym_t *, pqinf_t *));
+extern sym_t *addarray __P((sym_t *, int, int));
+extern sym_t *addfunc __P((sym_t *, sym_t *));
+extern void chkfdef __P((sym_t *, int));
+extern sym_t *dname __P((sym_t *));
+extern sym_t *iname __P((sym_t *));
+extern type_t *mktag __P((sym_t *, tspec_t, int, int));
+extern const char *scltoa __P((scl_t));
+extern type_t *compltag __P((type_t *, sym_t *));
+extern sym_t *ename __P((sym_t *, int, int));
+extern void decl1ext __P((sym_t *, int));
+extern void cpuinfo __P((sym_t *, sym_t *));
+extern int isredec __P((sym_t *, int *));
+extern int eqtype __P((type_t *, type_t *, int, int, int *));
+extern void compltyp __P((sym_t *, sym_t *));
+extern sym_t *decl1arg __P((sym_t *, int));
+extern void cluparg __P((void));
+extern void decl1loc __P((sym_t *, int));
+extern sym_t *aname __P((void));
+extern void globclup __P((void));
+extern sym_t *decl1abs __P((sym_t *));
+extern void chksz __P((sym_t *));
+extern void setsflg __P((sym_t *));
+extern void setuflg __P((sym_t *, int, int));
+extern void chkusage __P((dinfo_t *));
+extern void chkusg1 __P((int, sym_t *));
+extern void chkglsyms __P((void));
+extern void prevdecl __P((int, sym_t *));
+
+/*
+ * tree.c
+ */
+extern void initmtab __P((void));
+extern type_t *incref __P((type_t *, tspec_t));
+extern type_t *tincref __P((type_t *, tspec_t));
+extern tnode_t *getcnode __P((type_t *, val_t *));
+extern tnode_t *getnnode __P((sym_t *, int));
+extern tnode_t *getsnode __P((strg_t *));
+extern sym_t *strmemb __P((tnode_t *, op_t, sym_t *));
+extern tnode_t *build __P((op_t, tnode_t *, tnode_t *));
+extern tnode_t *cconv __P((tnode_t *));
+extern int typeok __P((op_t, int, tnode_t *, tnode_t *));
+extern tnode_t *promote __P((op_t, int, tnode_t *));
+extern tnode_t *convert __P((op_t, int, type_t *, tnode_t *));
+extern void cvtcon __P((op_t, int, type_t *, val_t *, val_t *));
+extern const char *tyname __P((type_t *));
+extern tnode_t *bldszof __P((type_t *));
+extern tnode_t *cast __P((tnode_t *, type_t *));
+extern tnode_t *funcarg __P((tnode_t *, tnode_t *));
+extern tnode_t *funccall __P((tnode_t *, tnode_t *));
+extern val_t *constant __P((tnode_t *));
+extern void expr __P((tnode_t *, int, int));
+extern void chkmisc __P((tnode_t *, int, int, int, int, int, int));
+extern int conaddr __P((tnode_t *, sym_t **, ptrdiff_t *));
+extern strg_t *catstrg __P((strg_t *, strg_t *));
+
+/*
+ * func.c
+ */
+extern sym_t *funcsym;
+extern int reached;
+extern int rchflg;
+extern int ftflg;
+extern int nargusg;
+extern pos_t aupos;
+extern int nvararg;
+extern pos_t vapos;
+extern int prflstrg;
+extern pos_t prflpos;
+extern int scflstrg;
+extern pos_t scflpos;
+extern int ccflg;
+extern int llibflg;
+extern int nowarn;
+extern int plibflg;
+extern int quadflg;
+
+extern void pushctrl __P((int));
+extern void popctrl __P((int));
+extern void chkreach __P((void));
+extern void funcdef __P((sym_t *));
+extern void funcend __P((void));
+extern void label __P((int, sym_t *, tnode_t *));
+extern void if1 __P((tnode_t *));
+extern void if2 __P((void));
+extern void if3 __P((int));
+extern void switch1 __P((tnode_t *));
+extern void switch2 __P((void));
+extern void while1 __P((tnode_t *));
+extern void while2 __P((void));
+extern void do1 __P((void));
+extern void do2 __P((tnode_t *));
+extern void for1 __P((tnode_t *, tnode_t *, tnode_t *));
+extern void for2 __P((void));
+extern void dogoto __P((sym_t *));
+extern void docont __P((void));
+extern void dobreak __P((void));
+extern void doreturn __P((tnode_t *));
+extern void glclup __P((int));
+extern void argsused __P((int));
+extern void constcond __P((int));
+extern void fallthru __P((int));
+extern void notreach __P((int));
+extern void lintlib __P((int));
+extern void linted __P((int));
+extern void varargs __P((int));
+extern void printflike __P((int));
+extern void scanflike __P((int));
+extern void protolib __P((int));
+extern void longlong __P((int));
+
+/*
+ * init.c
+ */
+extern int initerr;
+extern sym_t *initsym;
+extern int startinit;
+
+extern void prepinit __P((void));
+extern void initrbr __P((void));
+extern void initlbr __P((void));
+extern void mkinit __P((tnode_t *));
+
+/*
+ * emit.c
+ */
+extern void outtype __P((type_t *));
+extern const char *ttos __P((type_t *));
+extern void outsym __P((sym_t *, scl_t, def_t));
+extern void outfdef __P((sym_t *, pos_t *, int, int, sym_t *));
+extern void outcall __P((tnode_t *, int, int));
+extern void outusg __P((sym_t *));
diff --git a/usr.bin/xlint/lint1/func.c b/usr.bin/xlint/lint1/func.c
new file mode 100644
index 0000000..5d3a172
--- /dev/null
+++ b/usr.bin/xlint/lint1/func.c
@@ -0,0 +1,1261 @@
+/* $NetBSD: func.c,v 1.7 1995/10/02 17:31:40 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: func.c,v 1.7 1995/10/02 17:31:40 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "lint1.h"
+#include "y.tab.h"
+
+/*
+ * Contains a pointer to the symbol table entry of the current function
+ * definition.
+ */
+sym_t *funcsym;
+
+/* Is set as long as a statement can be reached. Must be set at level 0. */
+int reached = 1;
+
+/*
+ * Is set as long as NOTREACHED is in effect.
+ * Is reset everywhere where reached can become 0.
+ */
+int rchflg;
+
+/*
+ * In conjunction with reached ontrols printing of "fallthrough on ..."
+ * warnings.
+ * Reset by each statement and set by FALLTHROUGH, switch (switch1())
+ * and case (label()).
+ *
+ * Control statements if, for, while and switch do not reset ftflg because
+ * this must be done by the controled statement. At least for if this is
+ * important because ** FALLTHROUGH ** after "if (expr) stmnt" is evaluated
+ * befor the following token, wich causes reduction of above, is read.
+ * This means that ** FALLTHROUGH ** after "if ..." would always be ignored.
+ */
+int ftflg;
+
+/* Top element of stack for control statements */
+cstk_t *cstk;
+
+/*
+ * Number of arguments which will be checked for usage in following
+ * function definition. -1 stands for all arguments.
+ *
+ * The position of the last ARGSUSED comment is stored in aupos.
+ */
+int nargusg = -1;
+pos_t aupos;
+
+/*
+ * Number of arguments of the following function definition whose types
+ * shall be checked by lint2. -1 stands for all arguments.
+ *
+ * The position of the last VARARGS comment is stored in vapos.
+ */
+int nvararg = -1;
+pos_t vapos;
+
+/*
+ * Both prflstr and scflstrg contain the number of the argument which
+ * shall be used to check the types of remaining arguments (for PRINTFLIKE
+ * and SCANFLIKE).
+ *
+ * prflpos and scflpos are the positions of the last PRINTFLIKE or
+ * SCANFLIKE comment.
+ */
+int prflstrg = -1;
+int scflstrg = -1;
+pos_t prflpos;
+pos_t scflpos;
+
+/*
+ * Are both plibflg and llibflg set, prototypes are writen as function
+ * definitions to the output file.
+ */
+int plibflg;
+
+/*
+ * Nonzero means that no warnings about constands in conditional
+ * context are printed.
+ */
+int ccflg;
+
+/*
+ * llibflg is set if a lint library shall be created. The effect of
+ * llibflg is that all defined symbols are treated as used.
+ * (The LINTLIBRARY comment also resets vflag.)
+ */
+int llibflg;
+
+/*
+ * Nonzero if warnings are suppressed by a LINTED directive
+ */
+int nowarn;
+
+/*
+ * Nonzero if complaints about use of "long long" are suppressed in
+ * the next statement or declaration.
+ */
+int quadflg;
+
+/*
+ * Puts a new element at the top of the stack used for control statements.
+ */
+void
+pushctrl(env)
+ int env;
+{
+ cstk_t *ci;
+
+ ci = xcalloc(1, sizeof (cstk_t));
+ ci->c_env = env;
+ ci->c_nxt = cstk;
+ cstk = ci;
+}
+
+/*
+ * Removes the top element of the stack used for control statements.
+ */
+void
+popctrl(env)
+ int env;
+{
+ cstk_t *ci;
+ clst_t *cl;
+
+ if (cstk == NULL || cstk->c_env != env)
+ lerror("popctrl() 1");
+
+ cstk = (ci = cstk)->c_nxt;
+
+ while ((cl = ci->c_clst) != NULL) {
+ ci->c_clst = cl->cl_nxt;
+ free(cl);
+ }
+
+ if (ci->c_swtype != NULL)
+ free(ci->c_swtype);
+
+ free(ci);
+}
+
+/*
+ * Prints a warning if a statement cannot be reached.
+ */
+void
+chkreach()
+{
+ if (!reached && !rchflg) {
+ /* statement not reached */
+ warning(193);
+ reached = 1;
+ }
+}
+
+/*
+ * Called after a function declaration which introduces a function definition
+ * and before an (optional) old style argument declaration list.
+ *
+ * Puts all symbols declared in the Prototype or in an old style argument
+ * list back to the symbol table.
+ *
+ * Does the usual checking of storage class, type (return value),
+ * redeclaration etc..
+ */
+void
+funcdef(fsym)
+ sym_t *fsym;
+{
+ int n, warn;
+ sym_t *arg, *sym, *rdsym;
+
+ funcsym = fsym;
+
+ /*
+ * Put all symbols declared in the argument list back to the
+ * symbol table.
+ */
+ for (sym = dcs->d_fpsyms; sym != NULL; sym = sym->s_dlnxt) {
+ if (sym->s_blklev != -1) {
+ if (sym->s_blklev != 1)
+ lerror("funcdef() 1");
+ inssym(1, sym);
+ }
+ }
+
+ /*
+ * In osfunc() we did not know whether it is an old style function
+ * definition or only an old style declaration, if there are no
+ * arguments inside the argument list ("f()").
+ */
+ if (!fsym->s_type->t_proto && fsym->s_args == NULL)
+ fsym->s_osdef = 1;
+
+ chktyp(fsym);
+
+ /*
+ * chktyp() checks for almost all possible errors, but not for
+ * incomplete return values (these are allowed in declarations)
+ */
+ if (fsym->s_type->t_subt->t_tspec != VOID &&
+ incompl(fsym->s_type->t_subt)) {
+ /* cannot return incomplete type */
+ error(67);
+ }
+
+ fsym->s_def = DEF;
+
+ if (fsym->s_scl == TYPEDEF) {
+ fsym->s_scl = EXTERN;
+ /* illegal storage class */
+ error(8);
+ }
+
+ if (dcs->d_inline)
+ fsym->s_inline = 1;
+
+ /*
+ * Arguments in new style function declarations need a name.
+ * (void is already removed from the list of arguments)
+ */
+ n = 1;
+ for (arg = fsym->s_type->t_args; arg != NULL; arg = arg->s_nxt) {
+ if (arg->s_scl == ABSTRACT) {
+ if (arg->s_name != unnamed)
+ lerror("funcdef() 2");
+ /* formal parameter lacks name: param #%d */
+ error(59, n);
+ } else {
+ if (arg->s_name == unnamed)
+ lerror("funcdef() 3");
+ }
+ n++;
+ }
+
+ /*
+ * We must also remember the position. s_dpos is overwritten
+ * if this is an old style definition and we had already a
+ * prototype.
+ */
+ STRUCT_ASSIGN(dcs->d_fdpos, fsym->s_dpos);
+
+ if ((rdsym = dcs->d_rdcsym) != NULL) {
+
+ if (!isredec(fsym, (warn = 0, &warn))) {
+
+ /*
+ * Print nothing if the newly defined function
+ * is defined in old style. A better warning will
+ * be printed in cluparg().
+ */
+ if (warn && !fsym->s_osdef) {
+ /* redeclaration of %s */
+ (*(sflag ? error : warning))(27, fsym->s_name);
+ prevdecl(-1, rdsym);
+ }
+
+ /* copy usage information */
+ cpuinfo(fsym, rdsym);
+
+ /*
+ * If the old symbol was a prototype and the new
+ * one is none, overtake the position of the
+ * declaration of the prototype.
+ */
+ if (fsym->s_osdef && rdsym->s_type->t_proto)
+ STRUCT_ASSIGN(fsym->s_dpos, rdsym->s_dpos);
+
+ /* complete the type */
+ compltyp(fsym, rdsym);
+
+ /* once a function is inline it remains inline */
+ if (rdsym->s_inline)
+ fsym->s_inline = 1;
+
+ }
+
+ /* remove the old symbol from the symbol table */
+ rmsym(rdsym);
+
+ }
+
+ if (fsym->s_osdef && !fsym->s_type->t_proto) {
+ if (sflag && hflag && strcmp(fsym->s_name, "main") != 0)
+ /* function definition is not a prototyp */
+ warning(286);
+ }
+
+ if (dcs->d_notyp)
+ /* return value is implizitly declared to be int */
+ fsym->s_rimpl = 1;
+
+ reached = 1;
+}
+
+/*
+ * Called at the end of a function definition.
+ */
+void
+funcend()
+{
+ sym_t *arg;
+ int n;
+
+ if (reached) {
+ cstk->c_noretval = 1;
+ if (funcsym->s_type->t_subt->t_tspec != VOID &&
+ !funcsym->s_rimpl) {
+ /* func. %s falls off bottom without returning value */
+ warning(217, funcsym->s_name);
+ }
+ }
+
+ /*
+ * This warning is printed only if the return value was implizitly
+ * declared to be int. Otherwise the wrong return statement
+ * has already printed a warning.
+ */
+ if (cstk->c_noretval && cstk->c_retval && funcsym->s_rimpl)
+ /* function %s has return (e); and return; */
+ warning(216, funcsym->s_name);
+
+ /* Print warnings for unused arguments */
+ arg = dcs->d_fargs;
+ n = 0;
+ while (arg != NULL && (nargusg == -1 || n < nargusg)) {
+ chkusg1(dcs->d_asm, arg);
+ arg = arg->s_nxt;
+ n++;
+ }
+ nargusg = -1;
+
+ /*
+ * write the information about the function definition to the
+ * output file
+ * inline functions explicitely declared extern are written as
+ * declarations only.
+ */
+ if (dcs->d_scl == EXTERN && funcsym->s_inline) {
+ outsym(funcsym, funcsym->s_scl, DECL);
+ } else {
+ outfdef(funcsym, &dcs->d_fdpos, cstk->c_retval,
+ funcsym->s_osdef, dcs->d_fargs);
+ }
+
+ /*
+ * remove all symbols declared during argument declaration from
+ * the symbol table
+ */
+ if (dcs->d_nxt != NULL || dcs->d_ctx != EXTERN)
+ lerror("funcend() 1");
+ rmsyms(dcs->d_fpsyms);
+
+ /* must be set on level 0 */
+ reached = 1;
+}
+
+/*
+ * Process a label.
+ *
+ * typ type of the label (T_NAME, T_DEFAULT or T_CASE).
+ * sym symbol table entry of label if typ == T_NAME
+ * tn expression if typ == T_CASE
+ */
+void
+label(typ, sym, tn)
+ int typ;
+ sym_t *sym;
+ tnode_t *tn;
+{
+ cstk_t *ci;
+ clst_t *cl;
+ val_t *v, *nv;
+ tspec_t t;
+
+ switch (typ) {
+
+ case T_NAME:
+ if (sym->s_set) {
+ /* label %s redefined */
+ error(194, sym->s_name);
+ } else {
+ setsflg(sym);
+ }
+ break;
+
+ case T_CASE:
+
+ /* find the stack entry for the innermost switch statement */
+ for (ci = cstk; ci != NULL && !ci->c_switch; ci = ci->c_nxt) ;
+
+ if (ci == NULL) {
+ /* case not in switch */
+ error(195);
+ tn = NULL;
+ } else if (tn != NULL && tn->tn_op != CON) {
+ /* non-constant case expression */
+ error(197);
+ tn = NULL;
+ } else if (tn != NULL && !isityp(tn->tn_type->t_tspec)) {
+ /* non-integral case expression */
+ error(198);
+ tn = NULL;
+ }
+
+ if (tn != NULL) {
+
+ if (ci->c_swtype == NULL)
+ lerror("label() 1");
+
+ if (reached && !ftflg) {
+ if (hflag)
+ /* fallthrough on case statement */
+ warning(220);
+ }
+
+ t = tn->tn_type->t_tspec;
+ if (t == LONG || t == ULONG ||
+ t == QUAD || t == UQUAD) {
+ if (tflag)
+ /* case label must be of type ... */
+ warning(203);
+ }
+
+ /*
+ * get the value of the expression and convert it
+ * to the type of the switch expression
+ */
+ v = constant(tn);
+ nv = xcalloc(1, sizeof (val_t));
+ cvtcon(CASE, 0, ci->c_swtype, nv, v);
+ free(v);
+
+ /* look if we had this value already */
+ for (cl = ci->c_clst; cl != NULL; cl = cl->cl_nxt) {
+ if (cl->cl_val.v_quad == nv->v_quad)
+ break;
+ }
+ if (cl != NULL && isutyp(nv->v_tspec)) {
+ /* duplicate case in switch, %lu */
+ error(200, (u_long)nv->v_quad);
+ } else if (cl != NULL) {
+ /* duplicate case in switch, %ld */
+ error(199, (long)nv->v_quad);
+ } else {
+ /*
+ * append the value to the list of
+ * case values
+ */
+ cl = xcalloc(1, sizeof (clst_t));
+ STRUCT_ASSIGN(cl->cl_val, *nv);
+ cl->cl_nxt = ci->c_clst;
+ ci->c_clst = cl;
+ }
+ }
+ tfreeblk();
+ break;
+
+ case T_DEFAULT:
+
+ /* find the stack entry for the innermost switch statement */
+ for (ci = cstk; ci != NULL && !ci->c_switch; ci = ci->c_nxt) ;
+
+ if (ci == NULL) {
+ /* default outside switch */
+ error(201);
+ } else if (ci->c_default) {
+ /* duplicate default in switch */
+ error(202);
+ } else {
+ if (reached && !ftflg) {
+ if (hflag)
+ /* fallthrough on default statement */
+ warning(284);
+ }
+ ci->c_default = 1;
+ }
+ break;
+ };
+ reached = 1;
+}
+
+/*
+ * T_IF T_LPARN expr T_RPARN
+ */
+void
+if1(tn)
+ tnode_t *tn;
+{
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+ expr(tn, 0, 1);
+ pushctrl(T_IF);
+}
+
+/*
+ * if_without_else
+ * if_without_else T_ELSE
+ */
+void
+if2()
+{
+ cstk->c_rchif = reached ? 1 : 0;
+ reached = 1;
+}
+
+/*
+ * if_without_else
+ * if_without_else T_ELSE stmnt
+ */
+void
+if3(els)
+ int els;
+{
+ if (els) {
+ reached |= cstk->c_rchif;
+ } else {
+ reached = 1;
+ }
+ popctrl(T_IF);
+}
+
+/*
+ * T_SWITCH T_LPARN expr T_RPARN
+ */
+void
+switch1(tn)
+ tnode_t *tn;
+{
+ tspec_t t;
+ type_t *tp;
+
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+ if (tn != NULL && !isityp(tn->tn_type->t_tspec)) {
+ /* switch expression must have integral type */
+ error(205);
+ tn = NULL;
+ }
+ if (tn != NULL && tflag) {
+ t = tn->tn_type->t_tspec;
+ if (t == LONG || t == ULONG || t == QUAD || t == UQUAD) {
+ /* switch expr. must be of type `int' in trad. C */
+ warning(271);
+ }
+ }
+
+ /*
+ * Remember the type of the expression. Because its possible
+ * that (*tp) is allocated on tree memory the type must be
+ * duplicated. This is not too complicated because it is
+ * only an integer type.
+ */
+ tp = xcalloc(1, sizeof (type_t));
+ if (tn != NULL) {
+ tp->t_tspec = tn->tn_type->t_tspec;
+ if ((tp->t_isenum = tn->tn_type->t_isenum) != 0)
+ tp->t_enum = tn->tn_type->t_enum;
+ } else {
+ tp->t_tspec = INT;
+ }
+
+ expr(tn, 1, 0);
+
+ pushctrl(T_SWITCH);
+ cstk->c_switch = 1;
+ cstk->c_swtype = tp;
+
+ reached = rchflg = 0;
+ ftflg = 1;
+}
+
+/*
+ * switch_expr stmnt
+ */
+void
+switch2()
+{
+ int nenum, nclab;
+ sym_t *esym;
+ clst_t *cl;
+
+ if (cstk->c_swtype == NULL)
+ lerror("switch2() 1");
+
+ /*
+ * If the switch expression was of type enumeration, count the case
+ * labels and the number of enumerators. If both counts are not
+ * equal print a warning.
+ */
+ if (cstk->c_swtype->t_isenum) {
+ nenum = nclab = 0;
+ if (cstk->c_swtype->t_enum == NULL)
+ lerror("switch2() 2");
+ for (esym = cstk->c_swtype->t_enum->elem;
+ esym != NULL; esym = esym->s_nxt) {
+ nenum++;
+ }
+ for (cl = cstk->c_clst; cl != NULL; cl = cl->cl_nxt)
+ nclab++;
+ if (hflag && eflag && nenum != nclab && !cstk->c_default) {
+ /* enumeration value(s) not handled in switch */
+ warning(206);
+ }
+ }
+
+ if (cstk->c_break) {
+ /*
+ * end of switch alway reached (c_break is only set if the
+ * break statement can be reached).
+ */
+ reached = 1;
+ } else if (!cstk->c_default &&
+ (!hflag || !cstk->c_swtype->t_isenum || nenum != nclab)) {
+ /*
+ * there are possible values which are not handled in
+ * switch
+ */
+ reached = 1;
+ } /*
+ * otherwise the end of the switch expression is reached
+ * if the end of the last statement inside it is reached.
+ */
+
+ popctrl(T_SWITCH);
+}
+
+/*
+ * T_WHILE T_LPARN expr T_RPARN
+ */
+void
+while1(tn)
+ tnode_t *tn;
+{
+ if (!reached) {
+ /* loop not entered at top */
+ warning(207);
+ reached = 1;
+ }
+
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+ if (tn != NULL && !issclt(tn->tn_type->t_tspec)) {
+ /* controlling expressions must have scalar type */
+ error(204);
+ tn = NULL;
+ }
+
+ pushctrl(T_WHILE);
+ cstk->c_loop = 1;
+ if (tn != NULL && tn->tn_op == CON) {
+ if (isityp(tn->tn_type->t_tspec)) {
+ cstk->c_infinite = tn->tn_val->v_quad != 0;
+ } else {
+ cstk->c_infinite = tn->tn_val->v_ldbl != 0.0;
+ }
+ }
+
+ expr(tn, 0, 1);
+}
+
+/*
+ * while_expr stmnt
+ * while_expr error
+ */
+void
+while2()
+{
+ /*
+ * The end of the loop can be reached if it is no endless loop
+ * or there was a break statement which was reached.
+ */
+ reached = !cstk->c_infinite || cstk->c_break;
+ rchflg = 0;
+
+ popctrl(T_WHILE);
+}
+
+/*
+ * T_DO
+ */
+void
+do1()
+{
+ if (!reached) {
+ /* loop not entered at top */
+ warning(207);
+ reached = 1;
+ }
+
+ pushctrl(T_DO);
+ cstk->c_loop = 1;
+}
+
+/*
+ * do stmnt do_while_expr
+ * do error
+ */
+void
+do2(tn)
+ tnode_t *tn;
+{
+ /*
+ * If there was a continue statement the expression controlling the
+ * loop is reached.
+ */
+ if (cstk->c_cont)
+ reached = 1;
+
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+ if (tn != NULL && !issclt(tn->tn_type->t_tspec)) {
+ /* controlling expressions must have scalar type */
+ error(204);
+ tn = NULL;
+ }
+
+ if (tn != NULL && tn->tn_op == CON) {
+ if (isityp(tn->tn_type->t_tspec)) {
+ cstk->c_infinite = tn->tn_val->v_quad != 0;
+ } else {
+ cstk->c_infinite = tn->tn_val->v_ldbl != 0.0;
+ }
+ }
+
+ expr(tn, 0, 1);
+
+ /*
+ * The end of the loop is only reached if it is no endless loop
+ * or there was a break statement which could be reached.
+ */
+ reached = !cstk->c_infinite || cstk->c_break;
+ rchflg = 0;
+
+ popctrl(T_DO);
+}
+
+/*
+ * T_FOR T_LPARN opt_expr T_SEMI opt_expr T_SEMI opt_expr T_RPARN
+ */
+void
+for1(tn1, tn2, tn3)
+ tnode_t *tn1, *tn2, *tn3;
+{
+ /*
+ * If there is no initialisation expression it is possible that
+ * it is intended not to enter the loop at top.
+ */
+ if (tn1 != NULL && !reached) {
+ /* loop not entered at top */
+ warning(207);
+ reached = 1;
+ }
+
+ pushctrl(T_FOR);
+ cstk->c_loop = 1;
+
+ /*
+ * Store the tree memory for the reinitialisation expression.
+ * Also remember this expression itself. We must check it at
+ * the end of the loop to get "used but not set" warnings correct.
+ */
+ cstk->c_fexprm = tsave();
+ cstk->c_f3expr = tn3;
+ STRUCT_ASSIGN(cstk->c_fpos, curr_pos);
+ STRUCT_ASSIGN(cstk->c_cfpos, csrc_pos);
+
+ if (tn1 != NULL)
+ expr(tn1, 0, 0);
+
+ if (tn2 != NULL)
+ tn2 = cconv(tn2);
+ if (tn2 != NULL)
+ tn2 = promote(NOOP, 0, tn2);
+ if (tn2 != NULL && !issclt(tn2->tn_type->t_tspec)) {
+ /* controlling expressions must have scalar type */
+ error(204);
+ tn2 = NULL;
+ }
+ if (tn2 != NULL)
+ expr(tn2, 0, 1);
+
+ if (tn2 == NULL) {
+ cstk->c_infinite = 1;
+ } else if (tn2->tn_op == CON) {
+ if (isityp(tn2->tn_type->t_tspec)) {
+ cstk->c_infinite = tn2->tn_val->v_quad != 0;
+ } else {
+ cstk->c_infinite = tn2->tn_val->v_ldbl != 0.0;
+ }
+ }
+
+ /* Checking the reinitialisation expression is done in for2() */
+
+ reached = 1;
+}
+
+/*
+ * for_exprs stmnt
+ * for_exprs error
+ */
+void
+for2()
+{
+ pos_t cpos, cspos;
+ tnode_t *tn3;
+
+ if (cstk->c_cont)
+ reached = 1;
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+ STRUCT_ASSIGN(cspos, csrc_pos);
+
+ /* Restore the tree memory for the reinitialisation expression */
+ trestor(cstk->c_fexprm);
+ tn3 = cstk->c_f3expr;
+ STRUCT_ASSIGN(curr_pos, cstk->c_fpos);
+ STRUCT_ASSIGN(csrc_pos, cstk->c_cfpos);
+
+ /* simply "statement not reached" would be confusing */
+ if (!reached && !rchflg) {
+ /* end-of-loop code not reached */
+ warning(223);
+ reached = 1;
+ }
+
+ if (tn3 != NULL) {
+ expr(tn3, 0, 0);
+ } else {
+ tfreeblk();
+ }
+
+ STRUCT_ASSIGN(curr_pos, cpos);
+ STRUCT_ASSIGN(csrc_pos, cspos);
+
+ /* An endless loop without break will never terminate */
+ reached = cstk->c_break || !cstk->c_infinite;
+ rchflg = 0;
+
+ popctrl(T_FOR);
+}
+
+/*
+ * T_GOTO identifier T_SEMI
+ * T_GOTO error T_SEMI
+ */
+void
+dogoto(lab)
+ sym_t *lab;
+{
+ setuflg(lab, 0, 0);
+
+ chkreach();
+
+ reached = rchflg = 0;
+}
+
+/*
+ * T_BREAK T_SEMI
+ */
+void
+dobreak()
+{
+ cstk_t *ci;
+
+ ci = cstk;
+ while (ci != NULL && !ci->c_loop && !ci->c_switch)
+ ci = ci->c_nxt;
+
+ if (ci == NULL) {
+ /* break outside loop or switch */
+ error(208);
+ } else {
+ if (reached)
+ ci->c_break = 1;
+ }
+
+ if (bflag)
+ chkreach();
+
+ reached = rchflg = 0;
+}
+
+/*
+ * T_CONTINUE T_SEMI
+ */
+void
+docont()
+{
+ cstk_t *ci;
+
+ for (ci = cstk; ci != NULL && !ci->c_loop; ci = ci->c_nxt) ;
+
+ if (ci == NULL) {
+ /* continue outside loop */
+ error(209);
+ } else {
+ ci->c_cont = 1;
+ }
+
+ chkreach();
+
+ reached = rchflg = 0;
+}
+
+/*
+ * T_RETURN T_SEMI
+ * T_RETURN expr T_SEMI
+ */
+void
+doreturn(tn)
+ tnode_t *tn;
+{
+ tnode_t *ln, *rn;
+ cstk_t *ci;
+ op_t op;
+
+ for (ci = cstk; ci->c_nxt != NULL; ci = ci->c_nxt) ;
+
+ if (tn != NULL) {
+ ci->c_retval = 1;
+ } else {
+ ci->c_noretval = 1;
+ }
+
+ if (tn != NULL && funcsym->s_type->t_subt->t_tspec == VOID) {
+ /* void function %s cannot return value */
+ error(213, funcsym->s_name);
+ tfreeblk();
+ tn = NULL;
+ } else if (tn == NULL && funcsym->s_type->t_subt->t_tspec != VOID) {
+ /*
+ * Assume that the function has a return value only if it
+ * is explicitly declared.
+ */
+ if (!funcsym->s_rimpl)
+ /* function %s expects to return value */
+ warning(214, funcsym->s_name);
+ }
+
+ if (tn != NULL) {
+
+ /* Create a temporary node for the left side */
+ ln = tgetblk(sizeof (tnode_t));
+ ln->tn_op = NAME;
+ ln->tn_type = tduptyp(funcsym->s_type->t_subt);
+ ln->tn_type->t_const = 0;
+ ln->tn_lvalue = 1;
+ ln->tn_sym = funcsym; /* better than nothing */
+
+ tn = build(RETURN, ln, tn);
+
+ if (tn != NULL) {
+ rn = tn->tn_right;
+ while ((op = rn->tn_op) == CVT || op == PLUS)
+ rn = rn->tn_left;
+ if (rn->tn_op == AMPER && rn->tn_left->tn_op == NAME &&
+ rn->tn_left->tn_sym->s_scl == AUTO) {
+ /* %s returns pointer to automatic object */
+ warning(302, funcsym->s_name);
+ }
+ }
+
+ expr(tn, 1, 0);
+
+ } else {
+
+ chkreach();
+
+ }
+
+ reached = rchflg = 0;
+}
+
+/*
+ * Do some cleanup after a global declaration or definition.
+ * Especially remove informations about unused lint comments.
+ */
+void
+glclup(silent)
+ int silent;
+{
+ pos_t cpos;
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+
+ if (nargusg != -1) {
+ if (!silent) {
+ STRUCT_ASSIGN(curr_pos, aupos);
+ /* must precede function definition: %s */
+ warning(282, "ARGSUSED");
+ }
+ nargusg = -1;
+ }
+ if (nvararg != -1) {
+ if (!silent) {
+ STRUCT_ASSIGN(curr_pos, vapos);
+ /* must precede function definition: %s */
+ warning(282, "VARARGS");
+ }
+ nvararg = -1;
+ }
+ if (prflstrg != -1) {
+ if (!silent) {
+ STRUCT_ASSIGN(curr_pos, prflpos);
+ /* must precede function definition: %s */
+ warning(282, "PRINTFLIKE");
+ }
+ prflstrg = -1;
+ }
+ if (scflstrg != -1) {
+ if (!silent) {
+ STRUCT_ASSIGN(curr_pos, scflpos);
+ /* must precede function definition: %s */
+ warning(282, "SCANFLIKE");
+ }
+ scflstrg = -1;
+ }
+
+ STRUCT_ASSIGN(curr_pos, cpos);
+
+ dcs->d_asm = 0;
+}
+
+/*
+ * ARGSUSED comment
+ *
+ * Only the first n arguments of the following function are checked
+ * for usage. A missing argument is taken to be 0.
+ */
+void
+argsused(n)
+ int n;
+{
+ if (n == -1)
+ n = 0;
+
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "ARGSUSED");
+ return;
+ }
+ if (nargusg != -1) {
+ /* duplicate use of ** %s ** */
+ warning(281, "ARGSUSED");
+ }
+ nargusg = n;
+ STRUCT_ASSIGN(aupos, curr_pos);
+}
+
+/*
+ * VARARGS comment
+ *
+ * Makes that lint2 checks only the first n arguments for compatibility
+ * to the function definition. A missing argument is taken to be 0.
+ */
+void
+varargs(n)
+ int n;
+{
+ if (n == -1)
+ n = 0;
+
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "VARARGS");
+ return;
+ }
+ if (nvararg != -1) {
+ /* duplicate use of ** %s ** */
+ warning(281, "VARARGS");
+ }
+ nvararg = n;
+ STRUCT_ASSIGN(vapos, curr_pos);
+}
+
+/*
+ * PRINTFLIKE comment
+ *
+ * Check all arguments until the (n-1)-th as usual. The n-th argument is
+ * used the check the types of remaining arguments.
+ */
+void
+printflike(n)
+ int n;
+{
+ if (n == -1)
+ n = 0;
+
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "PRINTFLIKE");
+ return;
+ }
+ if (prflstrg != -1) {
+ /* duplicate use of ** %s ** */
+ warning(281, "PRINTFLIKE");
+ }
+ prflstrg = n;
+ STRUCT_ASSIGN(prflpos, curr_pos);
+}
+
+/*
+ * SCANFLIKE comment
+ *
+ * Check all arguments until the (n-1)-th as usual. The n-th argument is
+ * used the check the types of remaining arguments.
+ */
+void
+scanflike(n)
+ int n;
+{
+ if (n == -1)
+ n = 0;
+
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "SCANFLIKE");
+ return;
+ }
+ if (scflstrg != -1) {
+ /* duplicate use of ** %s ** */
+ warning(281, "SCANFLIKE");
+ }
+ scflstrg = n;
+ STRUCT_ASSIGN(scflpos, curr_pos);
+}
+
+/*
+ * Set the linenumber for a CONSTCOND comment. At this and the following
+ * line no warnings about constants in conditional contexts are printed.
+ */
+/* ARGSUSED */
+void
+constcond(n)
+ int n;
+{
+ ccflg = 1;
+}
+
+/*
+ * Suppress printing of "fallthrough on ..." warnings until next
+ * statement.
+ */
+/* ARGSUSED */
+void
+fallthru(n)
+ int n;
+{
+ ftflg = 1;
+}
+
+/*
+ * Stop warnings about statements which cannot be reached. Also tells lint
+ * that the following statements cannot be reached (e.g. after exit()).
+ */
+/* ARGSUSED */
+void
+notreach(n)
+ int n;
+{
+ reached = 0;
+ rchflg = 1;
+}
+
+/* ARGSUSED */
+void
+lintlib(n)
+ int n;
+{
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "LINTLIBRARY");
+ return;
+ }
+ llibflg = 1;
+ vflag = 0;
+}
+
+/*
+ * Suppress most warnings at the current and the following line.
+ */
+/* ARGSUSED */
+void
+linted(n)
+ int n;
+{
+ nowarn = 1;
+}
+
+/*
+ * PROTOTLIB in conjunction with LINTLIBRARY can be used to handle
+ * prototypes like function definitions. This is done if the argument
+ * to PROTOLIB is nonzero. Otherwise prototypes are handled normaly.
+ */
+void
+protolib(n)
+ int n;
+{
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "PROTOLIB");
+ return;
+ }
+ plibflg = n == 0 ? 0 : 1;
+}
+
+/*
+ * Set quadflg to nonzero which means that the next statement/declaration
+ * may use "long long" without an error or warning.
+ */
+/* ARGSUSED */
+void
+longlong(n)
+ int n;
+{
+ quadflg = 1;
+}
diff --git a/usr.bin/xlint/lint1/init.c b/usr.bin/xlint/lint1/init.c
new file mode 100644
index 0000000..dbd216b
--- /dev/null
+++ b/usr.bin/xlint/lint1/init.c
@@ -0,0 +1,513 @@
+/* $NetBSD: init.c,v 1.4 1995/10/02 17:21:37 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: init.c,v 1.4 1995/10/02 17:21:37 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+
+#include "lint1.h"
+
+/*
+ * initerr is set as soon as a fatal error occured in an initialisation.
+ * The effect is that the rest of the initialisation is ignored (parsed
+ * by yacc, expression trees built, but no initialisation takes place).
+ */
+int initerr;
+
+/* Pointer to the symbol which is to be initialized. */
+sym_t *initsym;
+
+/* Points to the top element of the initialisation stack. */
+istk_t *initstk;
+
+
+static void popi2 __P((void));
+static void popinit __P((int));
+static void pushinit __P((void));
+static void testinit __P((void));
+static void nextinit __P((int));
+static int strginit __P((tnode_t *));
+
+
+/*
+ * Initialize the initialisation stack by putting an entry for the variable
+ * which is to be initialized on it.
+ */
+void
+prepinit()
+{
+ istk_t *istk;
+
+ if (initerr)
+ return;
+
+ /* free memory used in last initialisation */
+ while ((istk = initstk) != NULL) {
+ initstk = istk->i_nxt;
+ free(istk);
+ }
+
+ /*
+ * If the type which is to be initialized is an incomplete type,
+ * it must be duplicated.
+ */
+ if (initsym->s_type->t_tspec == ARRAY && incompl(initsym->s_type))
+ initsym->s_type = duptyp(initsym->s_type);
+
+ istk = initstk = xcalloc(1, sizeof (istk_t));
+ istk->i_subt = initsym->s_type;
+ istk->i_cnt = 1;
+
+}
+
+static void
+popi2()
+{
+ istk_t *istk;
+ sym_t *m;
+
+ initstk = (istk = initstk)->i_nxt;
+ if (initstk == NULL)
+ lerror("popi2() 1");
+ free(istk);
+
+ istk = initstk;
+
+ istk->i_cnt--;
+ if (istk->i_cnt < 0)
+ lerror("popi2() 3");
+
+ /*
+ * If the removed element was a structure member, we must go
+ * to the next structure member.
+ */
+ if (istk->i_cnt > 0 && istk->i_type->t_tspec == STRUCT) {
+ do {
+ m = istk->i_mem = istk->i_mem->s_nxt;
+ if (m == NULL)
+ lerror("popi2() 2");
+ } while (m->s_field && m->s_name == unnamed);
+ istk->i_subt = m->s_type;
+ }
+}
+
+static void
+popinit(brace)
+ int brace;
+{
+ if (brace) {
+ /*
+ * Take all entries, including the first which requires
+ * a closing brace, from the stack.
+ */
+ do {
+ brace = initstk->i_brace;
+ popi2();
+ } while (!brace);
+ } else {
+ /*
+ * Take all entries which cannot be used for further
+ * initializers from the stack, but do this only if
+ * they do not require a closing brace.
+ */
+ while (!initstk->i_brace &&
+ initstk->i_cnt == 0 && !initstk->i_nolimit) {
+ popi2();
+ }
+ }
+}
+
+static void
+pushinit()
+{
+ istk_t *istk;
+ int cnt;
+ sym_t *m;
+
+ istk = initstk;
+
+ /* Extend an incomplete array type by one element */
+ if (istk->i_cnt == 0) {
+ /*
+ * Inside of other aggregate types must not be an incomplete
+ * type.
+ */
+ if (istk->i_nxt->i_nxt != NULL)
+ lerror("pushinit() 1");
+ istk->i_cnt = 1;
+ if (istk->i_type->t_tspec != ARRAY)
+ lerror("pushinit() 2");
+ istk->i_type->t_dim++;
+ /* from now its an complete type */
+ setcompl(istk->i_type, 0);
+ }
+
+ if (istk->i_cnt <= 0)
+ lerror("pushinit() 3");
+ if (istk->i_type != NULL && issclt(istk->i_type->t_tspec))
+ lerror("pushinit() 4");
+
+ initstk = xcalloc(1, sizeof (istk_t));
+ initstk->i_nxt = istk;
+ initstk->i_type = istk->i_subt;
+ if (initstk->i_type->t_tspec == FUNC)
+ lerror("pushinit() 5");
+
+ istk = initstk;
+
+ switch (istk->i_type->t_tspec) {
+ case ARRAY:
+ if (incompl(istk->i_type) && istk->i_nxt->i_nxt != NULL) {
+ /* initialisation of an incomplete type */
+ error(175);
+ initerr = 1;
+ return;
+ }
+ istk->i_subt = istk->i_type->t_subt;
+ istk->i_nolimit = incompl(istk->i_type);
+ istk->i_cnt = istk->i_type->t_dim;
+ break;
+ case UNION:
+ if (tflag)
+ /* initialisation of union is illegal in trad. C */
+ warning(238);
+ /* FALLTHROUGH */
+ case STRUCT:
+ if (incompl(istk->i_type)) {
+ /* initialisation of an incomplete type */
+ error(175);
+ initerr = 1;
+ return;
+ }
+ cnt = 0;
+ for (m = istk->i_type->t_str->memb; m != NULL; m = m->s_nxt) {
+ if (m->s_field && m->s_name == unnamed)
+ continue;
+ if (++cnt == 1) {
+ istk->i_mem = m;
+ istk->i_subt = m->s_type;
+ }
+ }
+ if (cnt == 0) {
+ /* cannot init. struct/union with no named member */
+ error(179);
+ initerr = 1;
+ return;
+ }
+ istk->i_cnt = istk->i_type->t_tspec == STRUCT ? cnt : 1;
+ break;
+ default:
+ istk->i_cnt = 1;
+ break;
+ }
+}
+
+static void
+testinit()
+{
+ istk_t *istk;
+
+ istk = initstk;
+
+ /*
+ * If a closing brace is expected we have at least one initializer
+ * too much.
+ */
+ if (istk->i_cnt == 0 && !istk->i_nolimit) {
+ switch (istk->i_type->t_tspec) {
+ case ARRAY:
+ /* too many array initializers */
+ error(173);
+ break;
+ case STRUCT:
+ case UNION:
+ /* too many struct/union initializers */
+ error(172);
+ break;
+ default:
+ /* too many initializers */
+ error(174);
+ break;
+ }
+ initerr = 1;
+ }
+}
+
+static void
+nextinit(brace)
+ int brace;
+{
+ if (!brace) {
+ if (initstk->i_type == NULL &&
+ !issclt(initstk->i_subt->t_tspec)) {
+ /* {}-enclosed initializer required */
+ error(181);
+ }
+ /*
+ * Make sure an entry with a scalar type is at the top
+ * of the stack.
+ */
+ if (!initerr)
+ testinit();
+ while (!initerr && (initstk->i_type == NULL ||
+ !issclt(initstk->i_type->t_tspec))) {
+ if (!initerr)
+ pushinit();
+ }
+ } else {
+ if (initstk->i_type != NULL &&
+ issclt(initstk->i_type->t_tspec)) {
+ /* invalid initializer */
+ error(176);
+ initerr = 1;
+ }
+ if (!initerr)
+ testinit();
+ if (!initerr)
+ pushinit();
+ if (!initerr)
+ initstk->i_brace = 1;
+ }
+}
+
+void
+initlbr()
+{
+ if (initerr)
+ return;
+
+ if ((initsym->s_scl == AUTO || initsym->s_scl == REG) &&
+ initstk->i_nxt == NULL) {
+ if (tflag && !issclt(initstk->i_subt->t_tspec))
+ /* no automatic aggregate initialization in trad. C*/
+ warning(188);
+ }
+
+ /*
+ * Remove all entries which cannot be used for further initializers
+ * and do not expect a closing brace.
+ */
+ popinit(0);
+
+ nextinit(1);
+}
+
+void
+initrbr()
+{
+ if (initerr)
+ return;
+
+ popinit(1);
+}
+
+void
+mkinit(tn)
+ tnode_t *tn;
+{
+ ptrdiff_t offs;
+ sym_t *sym;
+ tspec_t lt, rt;
+ tnode_t *ln;
+ struct mbl *tmem;
+ scl_t sc;
+
+ if (initerr || tn == NULL)
+ goto end;
+
+ sc = initsym->s_scl;
+
+ /*
+ * Do not test for automatic aggregat initialisation. If the
+ * initalizer starts with a brace we have the warning already.
+ * If not, an error will be printed that the initializer must
+ * be enclosed by braces.
+ */
+
+ /*
+ * Local initialisation of non-array-types with only one expression
+ * without braces is done by ASSIGN
+ */
+ if ((sc == AUTO || sc == REG) &&
+ initsym->s_type->t_tspec != ARRAY && initstk->i_nxt == NULL) {
+ ln = getnnode(initsym, 0);
+ ln->tn_type = tduptyp(ln->tn_type);
+ ln->tn_type->t_const = 0;
+ tn = build(ASSIGN, ln, tn);
+ expr(tn, 0, 0);
+ goto end;
+ }
+
+ /*
+ * Remove all entries which cannot be used for further initializers
+ * and do not require a closing brace.
+ */
+ popinit(0);
+
+ /* Initialisations by strings are done in strginit(). */
+ if (strginit(tn))
+ goto end;
+
+ nextinit(0);
+ if (initerr || tn == NULL)
+ goto end;
+
+ initstk->i_cnt--;
+
+ /* Create a temporary node for the left side. */
+ ln = tgetblk(sizeof (tnode_t));
+ ln->tn_op = NAME;
+ ln->tn_type = tduptyp(initstk->i_type);
+ ln->tn_type->t_const = 0;
+ ln->tn_lvalue = 1;
+ ln->tn_sym = initsym; /* better than nothing */
+
+ tn = cconv(tn);
+
+ lt = ln->tn_type->t_tspec;
+ rt = tn->tn_type->t_tspec;
+
+ if (!issclt(lt))
+ lerror("mkinit() 1");
+
+ if (!typeok(INIT, 0, ln, tn))
+ goto end;
+
+ /*
+ * Store the tree memory. This is nessesary because otherwise
+ * expr() would free it.
+ */
+ tmem = tsave();
+ expr(tn, 1, 0);
+ trestor(tmem);
+
+ if (isityp(lt) && ln->tn_type->t_isfield && !isityp(rt)) {
+ /*
+ * Bit-fields can be initialized in trad. C only by integer
+ * constants.
+ */
+ if (tflag)
+ /* bit-field initialisation is illegal in trad. C */
+ warning(186);
+ }
+
+ if (lt != rt || (initstk->i_type->t_isfield && tn->tn_op == CON))
+ tn = convert(INIT, 0, initstk->i_type, tn);
+
+ if (tn != NULL && tn->tn_op != CON) {
+ sym = NULL;
+ offs = 0;
+ if (conaddr(tn, &sym, &offs) == -1) {
+ if (sc == AUTO || sc == REG) {
+ /* non-constant initializer */
+ (void)gnuism(177);
+ } else {
+ /* non-constant initializer */
+ error(177);
+ }
+ }
+ }
+
+ end:
+ tfreeblk();
+}
+
+
+static int
+strginit(tn)
+ tnode_t *tn;
+{
+ tspec_t t;
+ istk_t *istk;
+ int len;
+ strg_t *strg;
+
+ if (tn->tn_op != STRING)
+ return (0);
+
+ istk = initstk;
+ strg = tn->tn_strg;
+
+ /*
+ * Check if we have an array type which can be initialized by
+ * the string.
+ */
+ if (istk->i_subt->t_tspec == ARRAY) {
+ t = istk->i_subt->t_subt->t_tspec;
+ if (!((strg->st_tspec == CHAR &&
+ (t == CHAR || t == UCHAR || t == SCHAR)) ||
+ (strg->st_tspec == WCHAR && t == WCHAR))) {
+ return (0);
+ }
+ /* Put the array at top of stack */
+ pushinit();
+ istk = initstk;
+ } else if (istk->i_type != NULL && istk->i_type->t_tspec == ARRAY) {
+ t = istk->i_type->t_subt->t_tspec;
+ if (!((strg->st_tspec == CHAR &&
+ (t == CHAR || t == UCHAR || t == SCHAR)) ||
+ (strg->st_tspec == WCHAR && t == WCHAR))) {
+ return (0);
+ }
+ /*
+ * If the array is already partly initialized, we are
+ * wrong here.
+ */
+ if (istk->i_cnt != istk->i_type->t_dim)
+ return (0);
+ } else {
+ return (0);
+ }
+
+ /* Get length without trailing NUL character. */
+ len = strg->st_len;
+
+ if (istk->i_nolimit) {
+ istk->i_nolimit = 0;
+ istk->i_type->t_dim = len + 1;
+ /* from now complete type */
+ setcompl(istk->i_type, 0);
+ } else {
+ if (istk->i_type->t_dim < len) {
+ /* non-null byte ignored in string initializer */
+ warning(187);
+ }
+ }
+
+ /* In every case the array is initialized completely. */
+ istk->i_cnt = 0;
+
+ return (1);
+}
diff --git a/usr.bin/xlint/lint1/lint.h b/usr.bin/xlint/lint1/lint.h
new file mode 100644
index 0000000..cadcd7a
--- /dev/null
+++ b/usr.bin/xlint/lint1/lint.h
@@ -0,0 +1,118 @@
+/* $NetBSD: lint.h,v 1.2 1995/07/03 21:24:18 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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 <sys/types.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "param.h"
+
+/*
+ * Type specifiers, used in type structures (type_t) and otherwere.
+ */
+typedef enum {
+ NOTSPEC,
+ SIGNED, /* keyword "signed", only used in the parser */
+ UNSIGN, /* keyword "unsigned", only used in the parser */
+ CHAR, /* char */
+ SCHAR, /* signed char */
+ UCHAR, /* unsigned char */
+ SHORT, /* (signed) short */
+ USHORT, /* unsigned short */
+ INT, /* (signed) int */
+ UINT, /* unsigned int */
+ LONG, /* (signed) long */
+ ULONG, /* unsigned long */
+ QUAD, /* (signed) long long */
+ UQUAD, /* unsigned long long */
+ FLOAT, /* float */
+ DOUBLE, /* double or, with tflag, long float */
+ LDOUBLE, /* long double */
+ VOID, /* void */
+ STRUCT, /* structure tag */
+ UNION, /* union tag */
+ ENUM, /* enum tag */
+ PTR, /* pointer */
+ ARRAY, /* array */
+ FUNC /* function */
+#define NTSPEC ((int)FUNC + 1)
+} tspec_t;
+
+/*
+ * size of types, name and classification
+ */
+typedef struct {
+ int tt_sz; /* size in bits */
+ int tt_psz; /* size, different from tt_sz
+ if pflag is set */
+ tspec_t tt_styp; /* signed counterpart */
+ tspec_t tt_utyp; /* unsigned counterpart */
+ u_int tt_isityp : 1; /* 1 if integer type */
+ u_int tt_isutyp : 1; /* 1 if unsigned integer type */
+ u_int tt_isftyp : 1; /* 1 if floating point type */
+ u_int tt_isatyp : 1; /* 1 if arithmetic type */
+ u_int tt_issclt : 1; /* 1 if scalar type */
+ char *tt_name; /* Bezeichnung des Typs */
+} ttab_t;
+
+#define size(t) (ttab[t].tt_sz)
+#define psize(t) (ttab[t].tt_psz)
+#define styp(t) (ttab[t].tt_styp)
+#define utyp(t) (ttab[t].tt_utyp)
+#define isityp(t) (ttab[t].tt_isityp)
+#define isutyp(t) (ttab[t].tt_isutyp)
+#define isftyp(t) (ttab[t].tt_isftyp)
+#define isatyp(t) (ttab[t].tt_isatyp)
+#define issclt(t) (ttab[t].tt_issclt)
+
+extern ttab_t ttab[];
+
+
+typedef enum {
+ NODECL, /* until now not declared */
+ DECL, /* declared */
+ TDEF, /* tentative defined */
+ DEF /* defined */
+} def_t;
+
+/*
+ * Following structure contains some data used for the output buffer.
+ */
+typedef struct ob {
+ char *o_buf; /* buffer */
+ char *o_end; /* first byte after buffer */
+ size_t o_len; /* length of buffer */
+ char *o_nxt; /* next free byte in buffer */
+} ob_t;
+
+#include "externs.h"
diff --git a/usr.bin/xlint/lint1/lint1.h b/usr.bin/xlint/lint1/lint1.h
new file mode 100644
index 0000000..019c98d
--- /dev/null
+++ b/usr.bin/xlint/lint1/lint1.h
@@ -0,0 +1,380 @@
+/* $NetBSD: lint1.h,v 1.6 1995/10/02 17:31:41 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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 "lint.h"
+#include "op.h"
+
+/*
+ * Describes the position of a declaration or anything else.
+ */
+typedef struct {
+ int p_line;
+ const char *p_file;
+} pos_t;
+
+/*
+ * Strings cannot be referenced to simply by a pointer to its first
+ * char. This is because strings can contain NUL characters other than the
+ * trailing NUL.
+ *
+ * Strings are stored with a trailing NUL.
+ */
+typedef struct strg {
+ tspec_t st_tspec; /* CHAR or WCHAR */
+ size_t st_len; /* length without trailing NUL */
+ union {
+ u_char *_st_cp;
+ wchar_t *_st_wcp;
+ } st_u;
+} strg_t;
+
+#define st_cp st_u._st_cp
+#define st_wcp st_u._st_wcp
+
+/*
+ * qualifiers (only for lex/yacc interface)
+ */
+typedef enum {
+ CONST, VOLATILE
+} tqual_t;
+
+/*
+ * Integer and floating point values are stored in this structure
+ */
+typedef struct {
+ tspec_t v_tspec;
+ int v_ansiu; /* set if an integer constant is
+ unsigned in ANSI C */
+ union {
+ quad_t _v_quad; /* integers */
+ ldbl_t _v_ldbl; /* floats */
+ } v_u;
+} val_t;
+
+#define v_quad v_u._v_quad
+#define v_ldbl v_u._v_ldbl
+
+/*
+ * Structures of type str_t uniqely identify structures. This can't
+ * be done in structures of type type_t, because these are copied
+ * if they must be modified. So it would not be possible to check
+ * if to structures are identical by comparing the pointers to
+ * the type structures.
+ *
+ * The typename is used if the structure is unnamed to identify
+ * the structure type in pass 2.
+ */
+typedef struct {
+ u_int size; /* size in bit */
+ u_int align : 15; /* alignment in bit */
+ u_int sincompl : 1; /* set if incomplete type */
+ struct sym *memb; /* list of members */
+ struct sym *stag; /* symbol table entry of tag */
+ struct sym *stdef; /* symbol table entry of first typename */
+} str_t;
+
+/*
+ * same as above for enums
+ */
+typedef struct {
+ u_int eincompl : 1; /* incomplete enum type */
+ struct sym *elem; /* list of enumerators */
+ struct sym *etag; /* symbol table entry of tag */
+ struct sym *etdef; /* symbol table entry of first typename */
+} enum_t;
+
+/*
+ * Types are represented by concatenation of structures of type type_t
+ * via t_subt.
+ */
+typedef struct type {
+ tspec_t t_tspec; /* type specifier */
+ u_int t_aincompl : 1; /* incomplete array type */
+ u_int t_const : 1; /* const modifier */
+ u_int t_volatile : 1; /* volatile modifier */
+ u_int t_proto : 1; /* function prototype (t_args valid) */
+ u_int t_vararg : 1; /* protoype with ... */
+ u_int t_typedef : 1; /* type defined with typedef */
+ u_int t_isfield : 1; /* type is bitfield */
+ u_int t_isenum : 1; /* type is (or was) enum (t_enum valid) */
+ union {
+ int _t_dim; /* dimension */
+ str_t *_t_str; /* struct/union tag */
+ enum_t *_t_enum; /* enum tag */
+ struct sym *_t_args; /* arguments (if t_proto) */
+ struct {
+ u_int _t_flen : 8; /* length of bit-field */
+ u_int _t_foffs : 24; /* offset of bit-field */
+ } _t_u;
+ } t_u;
+ struct type *t_subt; /* element type (arrays), return value
+ (functions), or type pointer points to */
+} type_t;
+
+#define t_dim t_u._t_dim
+#define t_str t_u._t_str
+#define t_field t_u._t_field
+#define t_enum t_u._t_enum
+#define t_args t_u._t_args
+#define t_flen t_u._t_u._t_flen
+#define t_foffs t_u._t_u._t_foffs
+
+/*
+ * types of symbols
+ */
+typedef enum {
+ FVFT, /* variables, functions, type names, enums */
+ FMOS, /* members of structs or unions */
+ FTAG, /* tags */
+ FLAB /* labels */
+} symt_t;
+
+/*
+ * storage classes
+ */
+typedef enum {
+ NOSCL,
+ EXTERN, /* external symbols (indep. of decl_t) */
+ STATIC, /* static symbols (local and global) */
+ AUTO, /* automatic symbols (except register) */
+ REG, /* register */
+ TYPEDEF, /* typedef */
+ STRTAG,
+ UNIONTAG,
+ ENUMTAG,
+ MOS, /* member of struct */
+ MOU, /* member of union */
+ ENUMCON, /* enumerator */
+ ABSTRACT, /* abstract symbol (sizeof, casts, unnamed argument) */
+ ARG, /* argument */
+ PARG, /* used in declaration stack during prototype
+ declaration */
+ INLINE /* only used by the parser */
+} scl_t;
+
+/*
+ * symbol table entry
+ */
+typedef struct sym {
+ const char *s_name; /* name */
+ pos_t s_dpos; /* position of last (prototype)definition,
+ prototypedeclaration, no-prototype-def.,
+ tentative definition or declaration,
+ in this order */
+ pos_t s_spos; /* position of first initialisation */
+ pos_t s_upos; /* position of first use */
+ symt_t s_kind; /* type of symbol */
+ u_int s_keyw : 1; /* keyword */
+ u_int s_field : 1; /* bit-field */
+ u_int s_set : 1; /* variable set, label defined */
+ u_int s_used : 1; /* variable/label used */
+ u_int s_arg : 1; /* symbol is function argument */
+ u_int s_reg : 1; /* symbol is register variable */
+ u_int s_defarg : 1; /* undefined symbol in old style function
+ definition */
+ u_int s_rimpl : 1; /* return value of function implizit decl. */
+ u_int s_osdef : 1; /* symbol stems from old style function def. */
+ u_int s_inline : 1; /* true if this is a inline function */
+ struct sym *s_xsym; /* for local declared external symbols pointer
+ to external symbol with same name */
+ def_t s_def; /* declared, tentative defined, defined */
+ scl_t s_scl; /* storage class */
+ int s_blklev; /* level of declaration, -1 if not in symbol
+ table */
+ type_t *s_type; /* type */
+ val_t s_value; /* value (if enumcon) */
+ union {
+ str_t *_s_st; /* tag, if it is a struct/union member */
+ enum_t *_s_et; /* tag, if it is a enumerator */
+ tspec_t _s_tsp; /* type (only for keywords) */
+ tqual_t _s_tqu; /* qualifier (only for keywords) */
+ struct sym *_s_args; /* arguments in old style function
+ definitions */
+ } u;
+ struct sym *s_link; /* next symbol with same hash value */
+ struct sym **s_rlink; /* pointer to s_link of prev. symbol */
+ struct sym *s_nxt; /* next struct/union member, enumerator,
+ argument */
+ struct sym *s_dlnxt; /* next symbol declared on same level */
+} sym_t;
+
+#define s_styp u._s_st
+#define s_etyp u._s_et
+#define s_tspec u._s_tsp
+#define s_tqual u._s_tqu
+#define s_args u._s_args
+
+/*
+ * Used to keep some informations about symbols before they are entered
+ * into the symbol table.
+ */
+typedef struct sbuf {
+ const char *sb_name; /* name of symbol */
+ size_t sb_len; /* length (without '\0') */
+ int sb_hash; /* hash value */
+ sym_t *sb_sym; /* symbol table entry */
+ struct sbuf *sb_nxt; /* for freelist */
+} sbuf_t;
+
+
+/*
+ * tree node
+ */
+typedef struct tnode {
+ op_t tn_op; /* operator */
+ type_t *tn_type; /* type */
+ u_int tn_lvalue : 1; /* node is lvalue */
+ u_int tn_cast : 1; /* if tn_op == CVT its an explizit cast */
+ u_int tn_parn : 1; /* node parenthesized */
+ union {
+ struct {
+ struct tnode *_tn_left; /* (left) operand */
+ struct tnode *_tn_right; /* right operand */
+ } tn_s;
+ sym_t *_tn_sym; /* symbol if op == NAME */
+ val_t *_tn_val; /* value if op == CON */
+ strg_t *_tn_strg; /* string if op == STRING */
+ } tn_u;
+} tnode_t;
+
+#define tn_left tn_u.tn_s._tn_left
+#define tn_right tn_u.tn_s._tn_right
+#define tn_sym tn_u._tn_sym
+#define tn_val tn_u._tn_val
+#define tn_strg tn_u._tn_strg
+
+/*
+ * For nested declarations a stack exists, which holds all information
+ * needed for the current level. dcs points to the top element of this
+ * stack.
+ *
+ * ctx describes the context of the current declaration. Its value is
+ * one of
+ * EXTERN global declarations
+ * MOS oder MOU declarations of struct or union members
+ * ENUMCON declarations of enums
+ * ARG declaration of arguments in old style function definitions
+ * PARG declaration of arguments in function prototypes
+ * AUTO declaration of local symbols
+ * ABSTRACT abstract declarations (sizeof, casts)
+ *
+ */
+typedef struct dinfo {
+ tspec_t d_atyp; /* VOID, CHAR, INT, FLOAT or DOUBLE */
+ tspec_t d_smod; /* SIGNED or UNSIGN */
+ tspec_t d_lmod; /* SHORT, LONG or QUAD */
+ scl_t d_scl; /* storage class */
+ type_t *d_type; /* after deftyp() pointer to the type used
+ for all declarators */
+ sym_t *d_rdcsym; /* redeclared symbol */
+ int d_offset; /* offset of next structure member */
+ int d_stralign; /* alignment required for current structure */
+ scl_t d_ctx; /* context of declaration */
+ u_int d_const : 1; /* const in declaration specifiers */
+ u_int d_volatile : 1; /* volatile in declaration specifiers */
+ u_int d_inline : 1; /* inline in declaration specifiers */
+ u_int d_mscl : 1; /* multiple storage classes */
+ u_int d_terr : 1; /* invalid type combination */
+ u_int d_nedecl : 1; /* 1 if at least a tag is declared */
+ u_int d_vararg : 1; /* ... in in current function decl. */
+ u_int d_proto : 1; /* current funct. decl. is prototype */
+ u_int d_notyp : 1; /* set if no type specifier was present */
+ u_int d_asm : 1; /* set if d_ctx == AUTO and asm() present */
+ type_t *d_tagtyp; /* tag during member declaration */
+ sym_t *d_fargs; /* list of arguments during function def. */
+ pos_t d_fdpos; /* position of function definition */
+ sym_t *d_dlsyms; /* first symbol declared at this level */
+ sym_t **d_ldlsym; /* points to s_dlnxt in last symbol decl.
+ at this level */
+ sym_t *d_fpsyms; /* symbols defined in prototype */
+ struct dinfo *d_nxt; /* next level */
+} dinfo_t;
+
+/*
+ * Type of stack which is used for initialisation of aggregate types.
+ */
+typedef struct istk {
+ type_t *i_type; /* type of initialisation */
+ type_t *i_subt; /* type of next level */
+ u_int i_brace : 1; /* need } for pop */
+ u_int i_nolimit : 1; /* incomplete array type */
+ sym_t *i_mem; /* next structure member */
+ int i_cnt; /* # of remaining elements */
+ struct istk *i_nxt; /* previous level */
+} istk_t;
+
+/*
+ * Used to collect information about pointers and qualifiers in
+ * declarators.
+ */
+typedef struct pqinf {
+ int p_pcnt; /* number of asterisks */
+ u_int p_const : 1;
+ u_int p_volatile : 1;
+ struct pqinf *p_nxt;
+} pqinf_t;
+
+/*
+ * Case values are stored in a list of type clst_t.
+ */
+typedef struct clst {
+ val_t cl_val;
+ struct clst *cl_nxt;
+} clst_t;
+
+/*
+ * Used to keep informations about nested control statements.
+ */
+typedef struct cstk {
+ int c_env; /* type of statement (T_IF, ...) */
+ u_int c_loop : 1; /* continue && break are valid */
+ u_int c_switch : 1; /* case && break are valid */
+ u_int c_break : 1; /* loop/switch has break */
+ u_int c_cont : 1; /* loop has continue */
+ u_int c_default : 1; /* switch has default */
+ u_int c_infinite : 1; /* break condition always false
+ (for (;;), while (1)) */
+ u_int c_rchif : 1; /* end of if-branch reached */
+ u_int c_noretval : 1; /* had "return;" */
+ u_int c_retval : 1; /* had "return (e);" */
+ type_t *c_swtype; /* type of switch expression */
+ clst_t *c_clst; /* list of case values */
+ struct mbl *c_fexprm; /* saved memory for end of loop
+ expression in for() */
+ tnode_t *c_f3expr; /* end of loop expr in for() */
+ pos_t c_fpos; /* position of end of loop expr */
+ pos_t c_cfpos; /* same for csrc_pos */
+ struct cstk *c_nxt; /* outer control statement */
+} cstk_t;
+
+#include "externs1.h"
diff --git a/usr.bin/xlint/lint1/main1.c b/usr.bin/xlint/lint1/main1.c
new file mode 100644
index 0000000..0add206
--- /dev/null
+++ b/usr.bin/xlint/lint1/main1.c
@@ -0,0 +1,183 @@
+/* $NetBSD: main1.c,v 1.3 1995/10/02 17:29:56 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: main1.c,v 1.3 1995/10/02 17:29:56 jpo Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+
+#include "lint1.h"
+
+/* set yydebug to 1*/
+int yflag;
+
+/*
+ * Print warnings if an assignment of an integertype to another integertype
+ * causes an implizit narrowing conversion. If aflag is 1, these warnings
+ * are printed only if the source type is at least as wide as long. If aflag
+ * is greather then 1, they are always printed.
+ */
+int aflag;
+
+/* Print a warning if a break statement cannot be reached. */
+int bflag;
+
+/* Print warnings for pointer casts. */
+int cflag;
+
+/* Print various debug information. */
+int dflag;
+
+/* Perform stricter checking of enum types and operations on enum types. */
+int eflag;
+
+/* Print complete pathnames, not only the basename. */
+int Fflag;
+
+/* Enable some extensions of gcc */
+int gflag;
+
+/*
+ * Apply a number of heuristic tests to attempt to intuit bugs, improve
+ * style, and reduce waste.
+ */
+int hflag;
+
+/* Attempt to check portability to other dialects of C. */
+int pflag;
+
+/*
+ * In case of redeclarations/redefinitions print the location of the
+ * previous declaration/definition.
+ */
+int rflag;
+
+/* Strict ANSI C mode. */
+int sflag;
+
+/* Traditional C mode. */
+int tflag;
+
+/*
+ * Complain about functions and external variables used and not defined,
+ * or defined and not used.
+ */
+int uflag = 1;
+
+/* Complain about unused function arguments. */
+int vflag = 1;
+
+/* Complain about structures which are never defined. */
+int zflag = 1;
+
+static void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+
+ while ((c = getopt(argc, argv, "abcdeghprstuvyzF")) != -1) {
+ switch (c) {
+ case 'a': aflag++; break;
+ case 'b': bflag = 1; break;
+ case 'c': cflag = 1; break;
+ case 'd': dflag = 1; break;
+ case 'e': eflag = 1; break;
+ case 'F': Fflag = 1; break;
+ case 'g': gflag = 1; break;
+ case 'h': hflag = 1; break;
+ case 'p': pflag = 1; break;
+ case 'r': rflag = 1; break;
+ case 's': sflag = 1; break;
+ case 't': tflag = 1; break;
+ case 'u': uflag = 0; break;
+ case 'v': vflag = 0; break;
+ case 'y': yflag = 1; break;
+ case 'z': zflag = 0; break;
+ case '?': usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 2)
+ usage();
+
+ /* open the input file */
+ if ((yyin = fopen(argv[0], "r")) == NULL)
+ err(1, "cannot open '%s'", argv[0]);
+
+ /* initialize output */
+ outopen(argv[1]);
+
+ if (yflag)
+ yydebug = 1;
+
+ initmem();
+ initdecl();
+ initscan();
+ initmtab();
+
+ yyparse();
+
+ /* Following warnings cannot be suppressed by LINTED */
+ nowarn = 0;
+
+ chkglsyms();
+
+ outclose();
+
+ return (nerr != 0);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage: lint1 [-abcdeghprstuvyzF] src dest\n");
+ exit(1);
+}
+
+void
+norecover()
+{
+ /* cannot recover from previous errors */
+ error(224);
+ exit(1);
+}
diff --git a/usr.bin/xlint/lint1/mem.c b/usr.bin/xlint/lint1/mem.c
new file mode 100644
index 0000000..71fba06
--- /dev/null
+++ b/usr.bin/xlint/lint1/mem.c
@@ -0,0 +1,91 @@
+/* $NetBSD: mem.c,v 1.2 1995/07/03 21:24:24 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: mem.c,v 1.2 1995/07/03 21:24:24 cgd Exp $";
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+
+#include "lint.h"
+
+void *
+xmalloc(s)
+ size_t s;
+{
+ void *p;
+
+ if ((p = malloc(s)) == NULL)
+ nomem();
+ return (p);
+}
+
+void *
+xcalloc(n, s)
+ size_t n, s;
+{
+ void *p;
+
+ if ((p = calloc(n, s)) == NULL)
+ nomem();
+ return (p);
+}
+
+void *
+xrealloc(p, s)
+ void *p;
+ size_t s;
+{
+ if ((p = realloc(p, s)) == NULL)
+ nomem();
+ return (p);
+}
+
+char *
+xstrdup(s)
+ const char *s;
+{
+ char *s2;
+
+ if ((s2 = strdup(s)) == NULL)
+ nomem();
+ return (s2);
+}
+
+void
+nomem()
+{
+ errx(1, "virtual memory exhausted");
+}
diff --git a/usr.bin/xlint/lint1/mem1.c b/usr.bin/xlint/lint1/mem1.c
new file mode 100644
index 0000000..df880b1
--- /dev/null
+++ b/usr.bin/xlint/lint1/mem1.c
@@ -0,0 +1,358 @@
+/* $NetBSD: mem1.c,v 1.2 1995/07/03 21:24:25 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: mem1.c,v 1.2 1995/07/03 21:24:25 cgd Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+
+#include "lint1.h"
+
+/*
+ * Filenames allocated by fnalloc() and fnnalloc() are shared.
+ */
+typedef struct fn {
+ char *fn_name;
+ size_t fn_len;
+ int fn_id;
+ struct fn *fn_nxt;
+} fn_t;
+
+static fn_t *fnames;
+
+static fn_t *srchfn __P((const char *, size_t));
+
+/*
+ * Look for a Filename of length l.
+ */
+static fn_t *
+srchfn(s, len)
+ const char *s;
+ size_t len;
+{
+ fn_t *fn;
+
+ for (fn = fnames; fn != NULL; fn = fn->fn_nxt) {
+ if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0)
+ break;
+ }
+ return (fn);
+}
+
+/*
+ * Return a shared string for filename s.
+ */
+const char *
+fnalloc(s)
+ const char *s;
+{
+ return (s != NULL ? fnnalloc(s, strlen(s)) : NULL);
+}
+
+const char *
+fnnalloc(s, len)
+ const char *s;
+ size_t len;
+{
+ fn_t *fn;
+
+ static int nxt_id = 0;
+
+ if (s == NULL)
+ return (NULL);
+
+ if ((fn = srchfn(s, len)) == NULL) {
+ fn = xmalloc(sizeof (fn_t));
+ /* Do not used strdup() because string is not NUL-terminated.*/
+ fn->fn_name = xmalloc(len + 1);
+ (void)memcpy(fn->fn_name, s, len);
+ fn->fn_name[len] = '\0';
+ fn->fn_len = len;
+ fn->fn_id = nxt_id++;
+ fn->fn_nxt = fnames;
+ fnames = fn;
+ /* Write id of this filename to the output file. */
+ outclr();
+ outint(fn->fn_id);
+ outchar('s');
+ outstrg(fn->fn_name);
+ }
+ return (fn->fn_name);
+}
+
+/*
+ * Get id of a filename.
+ */
+int
+getfnid(s)
+ const char *s;
+{
+ fn_t *fn;
+
+ if (s == NULL || (fn = srchfn(s, strlen(s))) == NULL)
+ return (-1);
+ return (fn->fn_id);
+}
+
+/*
+ * Memory for declarations and other things which must be available
+ * until the end of a block (or the end of the translation unit)
+ * are assoziated with the level (mblklev) of the block (or wiht 0).
+ * Because these memory is allocated in large blocks associated with
+ * a given level it can be freed easily at the end of a block.
+ */
+#define ML_INC ((size_t)32) /* Increment for length of *mblks */
+
+typedef struct mbl {
+ void *blk; /* beginning of memory block */
+ void *ffree; /* first free byte */
+ size_t nfree; /* # of free bytes */
+ size_t size; /* total size of memory block */
+ struct mbl *nxt; /* next block */
+} mbl_t;
+
+/*
+ * Array of pointers to lists of memory blocks. mblklev is used as
+ * index into this array.
+ */
+static mbl_t **mblks;
+
+/* number of elements in *mblks */
+static size_t nmblks;
+
+/* free list for memory blocks */
+static mbl_t *frmblks;
+
+/* length of new allocated memory blocks */
+static size_t mblklen;
+
+static void *xgetblk __P((mbl_t **, size_t));
+static void xfreeblk __P((mbl_t **));
+static mbl_t *xnewblk __P((void));
+
+static mbl_t *
+xnewblk()
+{
+ mbl_t *mb;
+ int prot, flags;
+
+ mb = xmalloc(sizeof (mbl_t));
+
+ /* use mmap instead of malloc to avoid malloc's size overhead */
+
+ prot = PROT_READ | PROT_WRITE;
+ flags = MAP_ANON | MAP_PRIVATE;
+ mb->blk = mmap(NULL, mblklen, prot, flags, -1, (off_t)0);
+ if (mb->blk == (void *)-1)
+ err(1, "can't map memory");
+ if (ALIGN((u_long)mb->blk) != (u_long)mb->blk)
+ errx(1, "mapped address is not aligned");
+
+ mb->size = mblklen;
+
+ return (mb);
+}
+
+/*
+ * Allocate new memory. If the first block of the list has not enough
+ * free space, or there is no first block, get a new block. The new
+ * block is taken from the free list or, if there is no block on the
+ * free list, is allocated using xnewblk(). If a new block is allocated
+ * it is initialized with zero. Blocks taken from the free list are
+ * zero'd in xfreeblk().
+ */
+static void *
+xgetblk(mbp, s)
+ mbl_t **mbp;
+ size_t s;
+{
+ mbl_t *mb;
+ void *p;
+
+ s = ALIGN(s);
+ if ((mb = *mbp) == NULL || mb->nfree < s) {
+ if ((mb = frmblks) == NULL) {
+ mb = xnewblk();
+ (void)memset(mb->blk, 0, mb->size);
+ } else {
+ frmblks = mb->nxt;
+ }
+ mb->ffree = mb->blk;
+ mb->nfree = mb->size;;
+ mb->nxt = *mbp;
+ *mbp = mb;
+ }
+ p = mb->ffree;
+ mb->ffree = (char *)mb->ffree + s;
+ mb->nfree -= s;
+ return (p);
+}
+
+/*
+ * Move all blocks from list *fmbp to free list. For each block, set all
+ * used memory to zero.
+ */
+static void
+xfreeblk(fmbp)
+ mbl_t **fmbp;
+{
+ mbl_t *mb;
+
+ while ((mb = *fmbp) != NULL) {
+ *fmbp = mb->nxt;
+ mb->nxt = frmblks;
+ frmblks = mb;
+ (void)memset(mb->blk, 0, mb->size - mb->nfree);
+ }
+}
+
+void
+initmem()
+{
+ int pgsz;
+
+ pgsz = getpagesize();
+ mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz;
+
+ mblks = xcalloc(nmblks = ML_INC, sizeof (mbl_t *));
+}
+
+
+/*
+ * Allocate memory associated with level l.
+ */
+void *
+getlblk(l, s)
+ int l;
+ size_t s;
+{
+ while (l >= nmblks) {
+ mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof (mbl_t *));
+ (void)memset(&mblks[nmblks], 0, ML_INC * sizeof (mbl_t *));
+ nmblks += ML_INC;
+ }
+ return (xgetblk(&mblks[l], s));
+}
+
+void *
+getblk(s)
+ size_t s;
+{
+ return (getlblk(mblklev, s));
+}
+
+/*
+ * Free all memory associated with level l.
+ */
+void
+freelblk(l)
+ int l;
+{
+ xfreeblk(&mblks[l]);
+}
+
+void
+freeblk()
+{
+ freelblk(mblklev);
+}
+
+/*
+ * tgetblk() returns memory which is associated with the current
+ * expression.
+ */
+static mbl_t *tmblk;
+
+void *
+tgetblk(s)
+ size_t s;
+{
+ return (xgetblk(&tmblk, s));
+}
+
+/*
+ * Get memory for a new tree node.
+ */
+tnode_t *
+getnode()
+{
+ return (tgetblk(sizeof (tnode_t)));
+}
+
+/*
+ * Free all memory which is allocated by the the current expression.
+ */
+void
+tfreeblk()
+{
+ xfreeblk(&tmblk);
+}
+
+/*
+ * Save the memory which is used by the current expression. This memory
+ * is not freed by the next tfreeblk() call. The pointer returned can be
+ * used to restore the memory.
+ */
+mbl_t *
+tsave()
+{
+ mbl_t *tmem;
+
+ tmem = tmblk;
+ tmblk = NULL;
+ return (tmem);
+}
+
+/*
+ * Free all memory used for the current expression and the memory used
+ * be a previous expression and saved by tsave(). The next call to
+ * tfreeblk() frees the restored memory.
+ */
+void
+trestor(tmem)
+ mbl_t *tmem;
+{
+ tfreeblk();
+ if (tmblk != NULL) {
+ free(tmblk->blk);
+ free(tmblk);
+ }
+ tmblk = tmem;
+}
diff --git a/usr.bin/xlint/lint1/op.h b/usr.bin/xlint/lint1/op.h
new file mode 100644
index 0000000..11f05a5
--- /dev/null
+++ b/usr.bin/xlint/lint1/op.h
@@ -0,0 +1,120 @@
+/* $NetBSD: op.h,v 1.2 1995/07/03 21:24:27 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+/*
+ * Various information about operators
+ */
+typedef struct {
+ u_int m_binary : 1; /* binary op. */
+ u_int m_logop : 1; /* logical op., result is int */
+ u_int m_rqint : 1; /* operands must have integer type */
+ u_int m_rqsclt : 1; /* operands must have scalar type */
+ u_int m_rqatyp : 1; /* operands must have arithmetic type */
+ u_int m_fold : 1; /* operands should be folded */
+ u_int m_vctx : 1; /* value context for left operand */
+ u_int m_tctx : 1; /* test context for left operand */
+ u_int m_balance : 1; /* op. requires balancing */
+ u_int m_sideeff : 1; /* op. has side effect */
+ u_int m_tlansiu : 1; /* warning if left op. is unsign. in ANSI C */
+ u_int m_transiu : 1; /* warning if right op. is unsign. in ANSI C */
+ u_int m_tpconf : 1; /* test possible precedence confusion */
+ u_int m_comp : 1; /* op. performs comparision */
+ u_int m_enumop : 1; /* valid operation on enums */
+ u_int m_badeop : 1; /* dubious operation on enums */
+ u_int m_eqwarn : 1; /* warning if on operand stems from == */
+ const char *m_name; /* name of op. */
+} mod_t;
+
+typedef enum {
+ NOOP = 0,
+ ARROW,
+ POINT,
+ NOT,
+ COMPL,
+ INC,
+ DEC,
+ INCBEF,
+ DECBEF,
+ INCAFT,
+ DECAFT,
+ UPLUS,
+ UMINUS,
+ STAR,
+ AMPER,
+ MULT,
+ DIV,
+ MOD,
+ PLUS,
+ MINUS,
+ SHL,
+ SHR,
+ LT,
+ LE,
+ GT,
+ GE,
+ EQ,
+ NE,
+ AND,
+ XOR,
+ OR,
+ LOGAND,
+ LOGOR,
+ QUEST,
+ COLON,
+ ASSIGN,
+ MULASS,
+ DIVASS,
+ MODASS,
+ ADDASS,
+ SUBASS,
+ SHLASS,
+ SHRASS,
+ ANDASS,
+ XORASS,
+ ORASS,
+ NAME,
+ CON,
+ STRING,
+ FSEL,
+ CALL,
+ COMMA,
+ CVT,
+ ICALL,
+ LOAD,
+ PUSH,
+ RETURN,
+ INIT, /* pseudo op, not used in trees */
+ CASE, /* pseudo op, not used in trees */
+ FARG /* pseudo op, not used in trees */
+#define NOPS ((int)FARG + 1)
+} op_t;
diff --git a/usr.bin/xlint/lint1/param.h b/usr.bin/xlint/lint1/param.h
new file mode 100644
index 0000000..17e266e
--- /dev/null
+++ b/usr.bin/xlint/lint1/param.h
@@ -0,0 +1,120 @@
+/* $NetBSD: param.h,v 1.4 1995/07/23 18:14:41 ragge Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+/*
+ * Minimun size of string buffer. If this is not enough, the buffer
+ * is enlarged in steps of STRBLEN bytes.
+ */
+#define STRBLEN 256
+
+/*
+ * This defines the size of memory blocks which are used to allocate
+ * memory in larger chunks.
+ */
+#define MBLKSIZ ((size_t)0x4000)
+
+/*
+ * Sizes of hash tables
+ * Should be a prime. Possible primes are
+ * 307, 401, 503, 601, 701, 809, 907, 1009, 1103, 1201, 1301, 1409, 1511.
+ *
+ * HSHSIZ1 symbol table 1st pass
+ * HSHSIZ2 symbol table 2nd pass
+ * THSHSIZ2 type table 2nd pass
+ */
+#define HSHSIZ1 503
+#define HSHSIZ2 1009
+#define THSHSIZ2 1009
+
+/*
+ * Should be set to 1 if the difference of two pointers is of type long
+ * or the value of sizeof is of type unsigned long.
+ */
+#ifdef __alpha__
+#define PTRDIFF_IS_LONG 1
+#define SIZEOF_IS_ULONG 1
+#elif __i386__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#elif __m68k__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#elif __ns32k__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#elif __sparc__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#elif __vax__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#else
+#error unknown machine type
+#endif
+
+/*
+ * Make sure this matches wchar_t.
+ */
+#define WCHAR SHORT
+
+#ifndef __GNUC__
+#ifndef lint
+#ifndef QUAD_MAX /* necessary for mkdep */
+#define QUAD_MAX LONG_MAX
+#define QUAD_MIN LONG_MIN
+#define UQUAD_MAX ULONG_MAX
+#endif
+typedef long quad_t;
+typedef u_long u_quad_t;
+#endif
+#endif
+
+
+/*
+ * long double only in ANSI C.
+ */
+#ifdef __STDC__
+typedef long double ldbl_t;
+#else
+typedef double ldbl_t;
+#endif
+
+/*
+ * Some traditional compilers are not able to assign structures.
+ */
+#ifdef __STDC__
+#define STRUCT_ASSIGN(dest, src) (dest) = (src)
+#else
+#define STRUCT_ASSIGN(dest, src) (void)memcpy(&(dest), &(src), \
+ sizeof (dest));
+#endif
diff --git a/usr.bin/xlint/lint1/scan.l b/usr.bin/xlint/lint1/scan.l
new file mode 100644
index 0000000..5e23c6b
--- /dev/null
+++ b/usr.bin/xlint/lint1/scan.l
@@ -0,0 +1,1426 @@
+%{
+/* $NetBSD: scan.l,v 1.8 1995/10/23 13:38:51 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: scan.l,v 1.8 1995/10/23 13:38:51 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <float.h>
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <err.h>
+
+#include "lint1.h"
+#include "y.tab.h"
+
+#define CHAR_MASK (~(~0 << CHAR_BIT))
+
+/* XXX declaration of strtouq() is missing in stdlib.h ? */
+extern u_quad_t strtouq __P((const char *, char **, int));
+
+/* Current position (its also updated when an included file is parsed) */
+pos_t curr_pos = { 1, "" };
+
+/*
+ * Current position in C source (not updated when an included file is
+ * parsed).
+ */
+pos_t csrc_pos = { 1, "" };
+
+static void incline __P((void));
+static void badchar __P((int));
+static sbuf_t *allocsb __P((void));
+static void freesb __P((sbuf_t *));
+static int inpc __P((void));
+static int hash __P((const char *));
+static sym_t *search __P((sbuf_t *));
+static int name __P((void));
+static int keyw __P((sym_t *));
+static int icon __P((int));
+static int fcon __P((void));
+static int operator __P((int, op_t));
+static int ccon __P((void));
+static int wccon __P((void));
+static int getescc __P((int));
+static void directive __P((void));
+static void comment __P((void));
+static int string __P((void));
+static int wcstrg __P((void));
+
+%}
+
+L [_A-Za-z]
+D [0-9]
+NZD [1-9]
+OD [0-7]
+HD [0-9A-Fa-f]
+EX ([eE][+-]?[0-9]+)
+
+%%
+
+{L}({L}|{D})* return (name());
+0{OD}*[lLuU]* return (icon(8));
+{NZD}{D}*[lLuU]* return (icon(10));
+0[xX]{HD}+[lLuU]* return (icon(16));
+{D}+\.{D}*{EX}?[fFlL]? |
+{D}+{EX}[fFlL]? |
+\.{D}+{EX}?[fFlL]? return (fcon());
+"=" return (operator(T_ASSIGN, ASSIGN));
+"*=" return (operator(T_OPASS, MULASS));
+"/=" return (operator(T_OPASS, DIVASS));
+"%=" return (operator(T_OPASS, MODASS));
+"+=" return (operator(T_OPASS, ADDASS));
+"-=" return (operator(T_OPASS, SUBASS));
+"<<=" return (operator(T_OPASS, SHLASS));
+">>=" return (operator(T_OPASS, SHRASS));
+"&=" return (operator(T_OPASS, ANDASS));
+"^=" return (operator(T_OPASS, XORASS));
+"|=" return (operator(T_OPASS, ORASS));
+"||" return (operator(T_LOGOR, LOGOR));
+"&&" return (operator(T_LOGAND, LOGAND));
+"|" return (operator(T_OR, OR));
+"&" return (operator(T_AND, AND));
+"^" return (operator(T_XOR, XOR));
+"==" return (operator(T_EQOP, EQ));
+"!=" return (operator(T_EQOP, NE));
+"<" return (operator(T_RELOP, LT));
+">" return (operator(T_RELOP, GT));
+"<=" return (operator(T_RELOP, LE));
+">=" return (operator(T_RELOP, GE));
+"<<" return (operator(T_SHFTOP, SHL));
+">>" return (operator(T_SHFTOP, SHR));
+"++" return (operator(T_INCDEC, INC));
+"--" return (operator(T_INCDEC, DEC));
+"->" return (operator(T_STROP, ARROW));
+"." return (operator(T_STROP, POINT));
+"+" return (operator(T_ADDOP, PLUS));
+"-" return (operator(T_ADDOP, MINUS));
+"*" return (operator(T_MULT, MULT));
+"/" return (operator(T_DIVOP, DIV));
+"%" return (operator(T_DIVOP, MOD));
+"!" return (operator(T_UNOP, NOT));
+"~" return (operator(T_UNOP, COMPL));
+"\"" return (string());
+"L\"" return (wcstrg());
+";" return (T_SEMI);
+"{" return (T_LBRACE);
+"}" return (T_RBRACE);
+"," return (T_COMMA);
+":" return (T_COLON);
+"?" return (T_QUEST);
+"[" return (T_LBRACK);
+"]" return (T_RBRACK);
+"(" return (T_LPARN);
+")" return (T_RPARN);
+"..." return (T_ELLIPSE);
+"'" return (ccon());
+"L'" return (wccon());
+^#.*$ directive();
+\n incline();
+\t|" "|\f|\v ;
+"/*" comment();
+. badchar(yytext[0]);
+
+%%
+
+static void
+incline()
+{
+ curr_pos.p_line++;
+ if (curr_pos.p_file == csrc_pos.p_file)
+ csrc_pos.p_line++;
+}
+
+static void
+badchar(c)
+ int c;
+{
+ /* unknown character \%o */
+ error(250, c);
+}
+
+/*
+ * Keywords.
+ * During initialisation they are written to the symbol table.
+ */
+static struct kwtab {
+ const char *kw_name; /* keyword */
+ int kw_token; /* token returned by yylex() */
+ scl_t kw_scl; /* storage class if kw_token T_SCLASS */
+ tspec_t kw_tspec; /* type spec. if kw_token T_TYPE or T_SOU */
+ tqual_t kw_tqual; /* type qual. fi kw_token T_QUAL */
+ u_int kw_stdc : 1; /* STDC keyword */
+ u_int kw_gcc : 1; /* GCC keyword */
+} kwtab[] = {
+ { "asm", T_ASM, 0, 0, 0, 0, 1 },
+ { "__asm", T_ASM, 0, 0, 0, 0, 0 },
+ { "__asm__", T_ASM, 0, 0, 0, 0, 0 },
+ { "auto", T_SCLASS, AUTO, 0, 0, 0, 0 },
+ { "break", T_BREAK, 0, 0, 0, 0, 0 },
+ { "case", T_CASE, 0, 0, 0, 0, 0 },
+ { "char", T_TYPE, 0, CHAR, 0, 0, 0 },
+ { "const", T_QUAL, 0, 0, CONST, 1, 0 },
+ { "__const__", T_QUAL, 0, 0, CONST, 0, 0 },
+ { "__const", T_QUAL, 0, 0, CONST, 0, 0 },
+ { "continue", T_CONTINUE, 0, 0, 0, 0, 0 },
+ { "default", T_DEFAULT, 0, 0, 0, 0, 0 },
+ { "do", T_DO, 0, 0, 0, 0, 0 },
+ { "double", T_TYPE, 0, DOUBLE, 0, 0, 0 },
+ { "else", T_ELSE, 0, 0, 0, 0, 0 },
+ { "enum", T_ENUM, 0, 0, 0, 0, 0 },
+ { "extern", T_SCLASS, EXTERN, 0, 0, 0, 0 },
+ { "float", T_TYPE, 0, FLOAT, 0, 0, 0 },
+ { "for", T_FOR, 0, 0, 0, 0, 0 },
+ { "goto", T_GOTO, 0, 0, 0, 0, 0 },
+ { "if", T_IF, 0, 0, 0, 0, 0 },
+ { "inline", T_SCLASS, INLINE, 0, 0, 0, 1 },
+ { "__inline__", T_SCLASS, INLINE, 0, 0, 0, 0 },
+ { "__inline", T_SCLASS, INLINE, 0, 0, 0, 0 },
+ { "int", T_TYPE, 0, INT, 0, 0, 0 },
+ { "long", T_TYPE, 0, LONG, 0, 0, 0 },
+ { "register", T_SCLASS, REG, 0, 0, 0, 0 },
+ { "return", T_RETURN, 0, 0, 0, 0, 0 },
+ { "short", T_TYPE, 0, SHORT, 0, 0, 0 },
+ { "signed", T_TYPE, 0, SIGNED, 0, 1, 0 },
+ { "__signed__", T_TYPE, 0, SIGNED, 0, 0, 0 },
+ { "__signed", T_TYPE, 0, SIGNED, 0, 0, 0 },
+ { "sizeof", T_SIZEOF, 0, 0, 0, 0, 0 },
+ { "static", T_SCLASS, STATIC, 0, 0, 0, 0 },
+ { "struct", T_SOU, 0, STRUCT, 0, 0, 0 },
+ { "switch", T_SWITCH, 0, 0, 0, 0, 0 },
+ { "typedef", T_SCLASS, TYPEDEF, 0, 0, 0, 0 },
+ { "union", T_SOU, 0, UNION, 0, 0, 0 },
+ { "unsigned", T_TYPE, 0, UNSIGN, 0, 0, 0 },
+ { "void", T_TYPE, 0, VOID, 0, 0, 0 },
+ { "volatile", T_QUAL, 0, 0, VOLATILE, 1, 0 },
+ { "__volatile__", T_QUAL, 0, 0, VOLATILE, 0, 0 },
+ { "__volatile", T_QUAL, 0, 0, VOLATILE, 0, 0 },
+ { "while", T_WHILE, 0, 0, 0, 0, 0 },
+ { NULL, 0, 0, 0, 0, 0, 0 }
+};
+
+/* Symbol table */
+static sym_t *symtab[HSHSIZ1];
+
+/* bit i of the entry with index i is set */
+u_quad_t qbmasks[sizeof(u_quad_t) * CHAR_BIT];
+
+/* least significant i bits are set in the entry with index i */
+u_quad_t qlmasks[sizeof(u_quad_t) * CHAR_BIT + 1];
+
+/* least significant i bits are not set in the entry with index i */
+u_quad_t qumasks[sizeof(u_quad_t) * CHAR_BIT + 1];
+
+/* free list for sbuf structures */
+static sbuf_t *sbfrlst;
+
+/* Typ of next expected symbol */
+symt_t symtyp;
+
+
+/*
+ * All keywords are written to the symbol table. This saves us looking
+ * in a extra table for each name we found.
+ */
+void
+initscan()
+{
+ struct kwtab *kw;
+ sym_t *sym;
+ int h, i;
+ u_quad_t uq;
+
+ for (kw = kwtab; kw->kw_name != NULL; kw++) {
+ if (kw->kw_stdc && tflag)
+ continue;
+ if (kw->kw_gcc && !gflag)
+ continue;
+ sym = getblk(sizeof (sym_t));
+ sym->s_name = kw->kw_name;
+ sym->s_keyw = 1;
+ sym->s_value.v_quad = kw->kw_token;
+ if (kw->kw_token == T_TYPE || kw->kw_token == T_SOU) {
+ sym->s_tspec = kw->kw_tspec;
+ } else if (kw->kw_token == T_SCLASS) {
+ sym->s_scl = kw->kw_scl;
+ } else if (kw->kw_token == T_QUAL) {
+ sym->s_tqual = kw->kw_tqual;
+ }
+ h = hash(sym->s_name);
+ if ((sym->s_link = symtab[h]) != NULL)
+ symtab[h]->s_rlink = &sym->s_link;
+ (symtab[h] = sym)->s_rlink = &symtab[h];
+ }
+
+ /* initialize bit-masks for quads */
+ for (i = 0; i < sizeof (u_quad_t) * CHAR_BIT; i++) {
+ qbmasks[i] = (u_quad_t)1 << i;
+ uq = ~(u_quad_t)0 << i;
+ qumasks[i] = uq;
+ qlmasks[i] = ~uq;
+ }
+ qumasks[i] = 0;
+ qlmasks[i] = ~(u_quad_t)0;
+}
+
+/*
+ * Get a free sbuf structure, if possible from the free list
+ */
+static sbuf_t *
+allocsb()
+{
+ sbuf_t *sb;
+
+ if ((sb = sbfrlst) != NULL) {
+ sbfrlst = sb->sb_nxt;
+ } else {
+ sb = xmalloc(sizeof (sbuf_t));
+ }
+ (void)memset(sb, 0, sizeof (sb));
+ return (sb);
+}
+
+/*
+ * Put a sbuf structure to the free list
+ */
+static void
+freesb(sb)
+ sbuf_t *sb;
+{
+ sb->sb_nxt = sbfrlst;
+ sbfrlst = sb;
+}
+
+/*
+ * Read a character and ensure that it is positive (except EOF).
+ * Increment line count(s) if necessary.
+ */
+static int
+inpc()
+{
+ int c;
+
+ if ((c = input()) != EOF && (c &= CHAR_MASK) == '\n')
+ incline();
+ return (c);
+}
+
+static int
+hash(s)
+ const char *s;
+{
+ u_int v;
+ const u_char *us;
+
+ v = 0;
+ for (us = (const u_char *)s; *us != '\0'; us++) {
+ v = (v << sizeof (v)) + *us;
+ v ^= v >> (sizeof (v) * CHAR_BIT - sizeof (v));
+ }
+ return (v % HSHSIZ1);
+}
+
+/*
+ * Lex has found a letter followed by zero or more letters or digits.
+ * It looks for a symbol in the symbol table with the same name. This
+ * symbol must either be a keyword or a symbol of the type required by
+ * symtyp (label, member, tag, ...).
+ *
+ * If it is a keyword, the token is returned. In some cases it is described
+ * more deeply by data written to yylval.
+ *
+ * If it is a symbol, T_NAME is returned and the pointer to a sbuf struct
+ * is stored in yylval. This struct contains the name of the symbol, it's
+ * length and hash value. If there is already a symbol of the same name
+ * and type in the symbol table, the sbuf struct also contains a pointer
+ * to the symbol table entry.
+ */
+static int
+name()
+{
+ char *s;
+ sbuf_t *sb;
+ sym_t *sym;
+ int tok;
+
+ sb = allocsb();
+ sb->sb_name = yytext;
+ sb->sb_len = yyleng;
+ sb->sb_hash = hash(yytext);
+
+ if ((sym = search(sb)) != NULL && sym->s_keyw) {
+ freesb(sb);
+ return (keyw(sym));
+ }
+
+ sb->sb_sym = sym;
+
+ if (sym != NULL) {
+ if (blklev < sym->s_blklev)
+ lerror("name() 1");
+ sb->sb_name = sym->s_name;
+ sb->sb_len = strlen(sym->s_name);
+ tok = sym->s_scl == TYPEDEF ? T_TYPENAME : T_NAME;
+ } else {
+ s = getblk(yyleng + 1);
+ (void)memcpy(s, yytext, yyleng + 1);
+ sb->sb_name = s;
+ sb->sb_len = yyleng;
+ tok = T_NAME;
+ }
+
+ yylval.y_sb = sb;
+ return (tok);
+}
+
+static sym_t *
+search(sb)
+ sbuf_t *sb;
+{
+ sym_t *sym;
+
+ for (sym = symtab[sb->sb_hash]; sym != NULL; sym = sym->s_link) {
+ if (strcmp(sym->s_name, sb->sb_name) == 0) {
+ if (sym->s_keyw || sym->s_kind == symtyp)
+ return (sym);
+ }
+ }
+
+ return (NULL);
+}
+
+static int
+keyw(sym)
+ sym_t *sym;
+{
+ int t;
+
+ if ((t = (int)sym->s_value.v_quad) == T_SCLASS) {
+ yylval.y_scl = sym->s_scl;
+ } else if (t == T_TYPE || t == T_SOU) {
+ yylval.y_tspec = sym->s_tspec;
+ } else if (t == T_QUAL) {
+ yylval.y_tqual = sym->s_tqual;
+ }
+ return (t);
+}
+
+/*
+ * Convert a string representing an integer into internal representation.
+ * The value is returned in yylval. icon() (and yylex()) returns T_CON.
+ */
+static int
+icon(base)
+ int base;
+{
+ int l_suffix, u_suffix;
+ int len;
+ const char *cp;
+ char c, *eptr;
+ tspec_t typ;
+ u_long ul;
+ u_quad_t uq;
+ int ansiu;
+ static tspec_t contypes[2][3] = {
+ { INT, LONG, QUAD },
+ { UINT, ULONG, UQUAD }
+ };
+
+ cp = yytext;
+ len = yyleng;
+
+ /* skip 0x */
+ if (base == 16) {
+ cp += 2;
+ len -= 2;
+ }
+
+ /* read suffixes */
+ l_suffix = u_suffix = 0;
+ for ( ; ; ) {
+ if ((c = cp[len - 1]) == 'l' || c == 'L') {
+ l_suffix++;
+ } else if (c == 'u' || c == 'U') {
+ u_suffix++;
+ } else {
+ break;
+ }
+ len--;
+ }
+ if (l_suffix > 2 || u_suffix > 1) {
+ /* malformed integer constant */
+ warning(251);
+ if (l_suffix > 2)
+ l_suffix = 2;
+ if (u_suffix > 1)
+ u_suffix = 1;
+ }
+ if (tflag && u_suffix != 0) {
+ /* suffix U is illegal in traditional C */
+ warning(97);
+ }
+ typ = contypes[u_suffix][l_suffix];
+
+ errno = 0;
+ if (l_suffix < 2) {
+ ul = strtoul(cp, &eptr, base);
+ } else {
+ uq = strtouq(cp, &eptr, base);
+ }
+ if (eptr != cp + len)
+ lerror("icon() 1");
+ if (errno != 0)
+ /* integer constant out of range */
+ warning(252);
+
+ /*
+ * If the value is to big for the current type, we must choose
+ * another type.
+ */
+ ansiu = 0;
+ switch (typ) {
+ case INT:
+ if (ul <= INT_MAX) {
+ /* ok */
+ } else if (ul <= (unsigned)UINT_MAX && base != 10) {
+ typ = UINT;
+ } else if (ul <= LONG_MAX) {
+ typ = LONG;
+ } else {
+ typ = ULONG;
+ }
+ if (typ == UINT || typ == ULONG) {
+ if (tflag) {
+ typ = LONG;
+ } else if (!sflag) {
+ /*
+ * Remember that the constant is unsigned
+ * only in ANSI C
+ */
+ ansiu = 1;
+ }
+ }
+ break;
+ case UINT:
+ if (ul > (u_int)UINT_MAX)
+ typ = ULONG;
+ break;
+ case LONG:
+ if (ul > LONG_MAX && !tflag) {
+ typ = ULONG;
+ if (!sflag)
+ ansiu = 1;
+ }
+ break;
+ case QUAD:
+ if (uq > QUAD_MAX && !tflag) {
+ typ = UQUAD;
+ if (!sflag)
+ ansiu = 1;
+ }
+ break;
+ /* LINTED (enumeration values not handled in switch) */
+ }
+
+ if (typ != QUAD && typ != UQUAD) {
+ if (isutyp(typ)) {
+ uq = ul;
+ } else {
+ uq = (quad_t)(long)ul;
+ }
+ }
+
+ uq = (u_quad_t)xsign((quad_t)uq, typ, -1);
+
+ (yylval.y_val = xcalloc(1, sizeof (val_t)))->v_tspec = typ;
+ yylval.y_val->v_ansiu = ansiu;
+ yylval.y_val->v_quad = (quad_t)uq;
+
+ return (T_CON);
+}
+
+/*
+ * Returns 1 if t is a signed type and the value is negative.
+ *
+ * len is the number of significant bits. If len is -1, len is set
+ * to the width of type t.
+ */
+int
+sign(q, t, len)
+ quad_t q;
+ tspec_t t;
+ int len;
+{
+ if (t == PTR || isutyp(t))
+ return (0);
+ return (msb(q, t, len));
+}
+
+int
+msb(q, t, len)
+ quad_t q;
+ tspec_t t;
+ int len;
+{
+ if (len <= 0)
+ len = size(t);
+ return ((q & qbmasks[len - 1]) != 0);
+}
+
+/*
+ * Extends the sign of q.
+ */
+quad_t
+xsign(q, t, len)
+ quad_t q;
+ tspec_t t;
+ int len;
+{
+ if (len <= 0)
+ len = size(t);
+
+ if (t == PTR || isutyp(t) || !sign(q, t, len)) {
+ q &= qlmasks[len];
+ } else {
+ q |= qumasks[len];
+ }
+ return (q);
+}
+
+/*
+ * Convert a string representing a floating point value into its interal
+ * representation. Type and value are returned in yylval. fcon()
+ * (and yylex()) returns T_CON.
+ * XXX Currently it is not possible to convert constants of type
+ * long double which are greater then DBL_MAX.
+ */
+static int
+fcon()
+{
+ const char *cp;
+ int len;
+ tspec_t typ;
+ char c, *eptr;
+ double d;
+ float f;
+
+ cp = yytext;
+ len = yyleng;
+
+ if ((c = cp[len - 1]) == 'f' || c == 'F') {
+ typ = FLOAT;
+ len--;
+ } else if (c == 'l' || c == 'L') {
+ typ = LDOUBLE;
+ len--;
+ } else {
+ typ = DOUBLE;
+ }
+
+ if (tflag && typ != DOUBLE) {
+ /* suffixes F and L are illegal in traditional C */
+ warning(98);
+ }
+
+ errno = 0;
+ d = strtod(cp, &eptr);
+ if (eptr != cp + len)
+ lerror("fcon() 1");
+ if (errno != 0)
+ /* floating-point constant out of range */
+ warning(248);
+
+ if (typ == FLOAT) {
+ f = (float)d;
+ if (isinf(f)) {
+ /* floating-point constant out of range */
+ warning(248);
+ f = f > 0 ? FLT_MAX : -FLT_MAX;
+ }
+ }
+
+ (yylval.y_val = xcalloc(1, sizeof (val_t)))->v_tspec = typ;
+ if (typ == FLOAT) {
+ yylval.y_val->v_ldbl = f;
+ } else {
+ yylval.y_val->v_ldbl = d;
+ }
+
+ return (T_CON);
+}
+
+static int
+operator(t, o)
+ int t;
+ op_t o;
+{
+ yylval.y_op = o;
+ return (t);
+}
+
+/*
+ * Called if lex found a leading \'.
+ */
+static int
+ccon()
+{
+ int n, val, c;
+ char cv;
+
+ n = 0;
+ val = 0;
+ while ((c = getescc('\'')) >= 0) {
+ val = (val << CHAR_BIT) + c;
+ n++;
+ }
+ if (c == -2) {
+ /* unterminated character constant */
+ error(253);
+ } else {
+ if (n > sizeof (int) || (n > 1 && (pflag || hflag))) {
+ /* too many characters in character constant */
+ error(71);
+ } else if (n > 1) {
+ /* multi-character character constant */
+ warning(294);
+ } else if (n == 0) {
+ /* empty character constant */
+ error(73);
+ }
+ }
+ if (n == 1) {
+ cv = (char)val;
+ val = cv;
+ }
+
+ yylval.y_val = xcalloc(1, sizeof (val_t));
+ yylval.y_val->v_tspec = INT;
+ yylval.y_val->v_quad = val;
+
+ return (T_CON);
+}
+
+/*
+ * Called if lex found a leading L\'
+ */
+static int
+wccon()
+{
+ static char buf[MB_LEN_MAX + 1];
+ int i, c;
+ wchar_t wc;
+
+ i = 0;
+ while ((c = getescc('\'')) >= 0) {
+ if (i < MB_CUR_MAX)
+ buf[i] = (char)c;
+ i++;
+ }
+
+ wc = 0;
+
+ if (c == -2) {
+ /* unterminated character constant */
+ error(253);
+ } else if (c == 0) {
+ /* empty character constant */
+ error(73);
+ } else {
+ if (i > MB_CUR_MAX) {
+ i = MB_CUR_MAX;
+ /* too many characters in character constant */
+ error(71);
+ } else {
+ buf[i] = '\0';
+ (void)mbtowc(NULL, NULL, 0);
+ if (mbtowc(&wc, buf, MB_CUR_MAX) < 0)
+ /* invalid multibyte character */
+ error(291);
+ }
+ }
+
+ yylval.y_val = xcalloc(1, sizeof (val_t));
+ yylval.y_val->v_tspec = WCHAR;
+ yylval.y_val->v_quad = wc;
+
+ return (T_CON);
+}
+
+/*
+ * Read a character which is part of a character constant or of a string
+ * and handle escapes.
+ *
+ * The Argument is the character which delimits the character constant or
+ * string.
+ *
+ * Returns -1 if the end of the character constant or string is reached,
+ * -2 if the EOF is reached, and the charachter otherwise.
+ */
+static int
+getescc(d)
+ int d;
+{
+ static int pbc = -1;
+ int n, c, v;
+
+ if (pbc == -1) {
+ c = inpc();
+ } else {
+ c = pbc;
+ pbc = -1;
+ }
+ if (c == d)
+ return (-1);
+ switch (c) {
+ case '\n':
+ /* newline in string or char constant */
+ error(254);
+ return (-2);
+ case EOF:
+ return (-2);
+ case '\\':
+ switch (c = inpc()) {
+ case '"':
+ if (tflag && d == '\'')
+ /* \" inside character constant undef. ... */
+ warning(262);
+ return ('"');
+ case '\'':
+ return ('\'');
+ case '?':
+ if (tflag)
+ /* \? undefined in traditional C */
+ warning(263);
+ return ('?');
+ case '\\':
+ return ('\\');
+ case 'a':
+ if (tflag)
+ /* \a undefined in traditional C */
+ warning(81);
+#ifdef __STDC__
+ return ('\a');
+#else
+ return ('\007');
+#endif
+ case 'b':
+ return ('\b');
+ case 'f':
+ return ('\f');
+ case 'n':
+ return ('\n');
+ case 'r':
+ return ('\r');
+ case 't':
+ return ('\t');
+ case 'v':
+ if (tflag)
+ /* \v undefined in traditional C */
+ warning(264);
+#ifdef __STDC__
+ return ('\v');
+#else
+ return ('\013');
+#endif
+ case '8': case '9':
+ /* bad octal digit %c */
+ warning(77, c);
+ /* FALLTHROUGH */
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ n = 3;
+ v = 0;
+ do {
+ v = (v << 3) + (c - '0');
+ c = inpc();
+ } while (--n && isdigit(c) && (tflag || c <= '7'));
+ if (tflag && n > 0 && isdigit(c))
+ /* bad octal digit %c */
+ warning(77, c);
+ pbc = c;
+ if (v > UCHAR_MAX) {
+ /* character escape does not fit in char. */
+ warning(76);
+ v &= CHAR_MASK;
+ }
+ return (v);
+ case 'x':
+ if (tflag)
+ /* \x undefined in traditional C */
+ warning(82);
+ v = 0;
+ n = 0;
+ while ((c = inpc()) >= 0 && isxdigit(c)) {
+ c = isdigit(c) ?
+ c - '0' : toupper(c) - 'A' + 10;
+ v = (v << 4) + c;
+ if (n >= 0) {
+ if ((v & ~CHAR_MASK) != 0) {
+ /* overflow in hex escape */
+ warning(75);
+ n = -1;
+ } else {
+ n++;
+ }
+ }
+ }
+ pbc = c;
+ if (n == 0) {
+ /* no hex digits follow \x */
+ error(74);
+ } if (n == -1) {
+ v &= CHAR_MASK;
+ }
+ return (v);
+ case '\n':
+ return (getescc(d));
+ case EOF:
+ return (-2);
+ default:
+ if (isprint(c)) {
+ /* dubious escape \%c */
+ warning(79, c);
+ } else {
+ /* dubious escape \%o */
+ warning(80, c);
+ }
+ }
+ }
+ return (c);
+}
+
+/*
+ * Called for preprocessor directives. Currently implemented are:
+ * # lineno
+ * # lineno "filename"
+ */
+static void
+directive()
+{
+ const char *cp, *fn;
+ char c, *eptr;
+ size_t fnl;
+ long ln;
+ static int first = 1;
+
+ /* Go to first non-whitespace after # */
+ for (cp = yytext + 1; (c = *cp) == ' ' || c == '\t'; cp++) ;
+
+ if (!isdigit(c)) {
+ error:
+ /* undefined or invalid # directive */
+ warning(255);
+ return;
+ }
+ ln = strtol(--cp, &eptr, 10);
+ if (cp == eptr)
+ goto error;
+ if ((c = *(cp = eptr)) != ' ' && c != '\t' && c != '\0')
+ goto error;
+ while ((c = *cp++) == ' ' || c == '\t') ;
+ if (c != '\0') {
+ if (c != '"')
+ goto error;
+ fn = cp;
+ while ((c = *cp) != '"' && c != '\0')
+ cp++;
+ if (c != '"')
+ goto error;
+ if ((fnl = cp++ - fn) > PATH_MAX)
+ goto error;
+ while ((c = *cp++) == ' ' || c == '\t') ;
+#if 0
+ if (c != '\0')
+ warning("extra character(s) after directive");
+#endif
+ curr_pos.p_file = fnnalloc(fn, fnl);
+ /*
+ * If this is the first directive, the name is the name
+ * of the C source file as specified at the command line.
+ * It is written to the output file.
+ */
+ if (first) {
+ csrc_pos.p_file = curr_pos.p_file;
+ outsrc(curr_pos.p_file);
+ first = 0;
+ }
+ }
+ curr_pos.p_line = (int)ln - 1;
+ if (curr_pos.p_file == csrc_pos.p_file)
+ csrc_pos.p_line = (int)ln - 1;
+}
+
+/*
+ * Handle lint comments. Following comments are currently understood:
+ * ARGSUSEDn
+ * CONSTCOND CONSTANTCOND CONSTANTCONDITION
+ * FALLTHRU FALLTHROUGH
+ * LINTLIBRARY
+ * LINTED NOSTRICT
+ * LONGLONG
+ * NOTREACHED
+ * PRINTFLIKEn
+ * PROTOLIB
+ * SCANFLIKEn
+ * VARARGSn
+ * If one of this comments is recognized, the arguments, if any, are
+ * parsed and a function which handles this comment is called.
+ */
+static void
+comment()
+{
+ int c, lc;
+ static struct {
+ const char *keywd;
+ int arg;
+ void (*func) __P((int));
+ } keywtab[] = {
+ { "ARGSUSED", 1, argsused },
+ { "CONSTCOND", 0, constcond },
+ { "CONSTANTCOND", 0, constcond },
+ { "CONSTANTCONDITION", 0, constcond },
+ { "FALLTHRU", 0, fallthru },
+ { "FALLTHROUGH", 0, fallthru },
+ { "LINTLIBRARY", 0, lintlib },
+ { "LINTED", 0, linted },
+ { "LONGLONG", 0, longlong },
+ { "NOSTRICT", 0, linted },
+ { "NOTREACHED", 0, notreach },
+ { "PRINTFLIKE", 1, printflike },
+ { "PROTOLIB", 1, protolib },
+ { "SCANFLIKE", 1, scanflike },
+ { "VARARGS", 1, varargs },
+ };
+ char keywd[32];
+ char arg[32];
+ int l, i, a;
+ int eoc;
+
+ eoc = 0;
+
+ /* Skip white spaces after the start of the comment */
+ while ((c = inpc()) != EOF && isspace(c)) ;
+
+ /* Read the potential keyword to keywd */
+ l = 0;
+ while (c != EOF && isupper(c) && l < sizeof (keywd) - 1) {
+ keywd[l++] = (char)c;
+ c = inpc();
+ }
+ keywd[l] = '\0';
+
+ /* look for the keyword */
+ for (i = 0; i < sizeof (keywtab) / sizeof (keywtab[0]); i++) {
+ if (strcmp(keywtab[i].keywd, keywd) == 0)
+ break;
+ }
+ if (i == sizeof (keywtab) / sizeof (keywtab[0]))
+ goto skip_rest;
+
+ /* skip white spaces after the keyword */
+ while (c != EOF && isspace(c))
+ c = inpc();
+
+ /* read the argument, if the keyword accepts one and there is one */
+ l = 0;
+ if (keywtab[i].arg) {
+ while (c != EOF && isdigit(c) && l < sizeof (arg) - 1) {
+ arg[l++] = (char)c;
+ c = inpc();
+ }
+ }
+ arg[l] = '\0';
+ a = l != 0 ? atoi(arg) : -1;
+
+ /* skip white spaces after the argument */
+ while (c != EOF && isspace(c))
+ c = inpc();
+
+ if (c != '*' || (c = inpc()) != '/') {
+ if (keywtab[i].func != linted)
+ /* extra characters in lint comment */
+ warning(257);
+ } else {
+ /*
+ * remember that we have already found the end of the
+ * comment
+ */
+ eoc = 1;
+ }
+
+ if (keywtab[i].func != NULL)
+ (*keywtab[i].func)(a);
+
+ skip_rest:
+ while (!eoc) {
+ lc = c;
+ if ((c = inpc()) == EOF) {
+ /* unterminated comment */
+ error(256);
+ break;
+ }
+ if (lc == '*' && c == '/')
+ eoc = 1;
+ }
+}
+
+/*
+ * Clear flags for lint comments LINTED, LONGLONG and CONSTCOND.
+ * clrwflgs() is called after function definitions and global and
+ * local declarations and definitions. It is also called between
+ * the controlling expression and the body of control statements
+ * (if, switch, for, while).
+ */
+void
+clrwflgs()
+{
+ nowarn = 0;
+ quadflg = 0;
+ ccflg = 0;
+}
+
+/*
+ * Strings are stored in a dynamically alloceted buffer and passed
+ * in yylval.y_xstrg to the parser. The parser or the routines called
+ * by the parser are responsible for freeing this buffer.
+ */
+static int
+string()
+{
+ u_char *s;
+ int c;
+ size_t len, max;
+ strg_t *strg;
+
+ s = xmalloc(max = 64);
+
+ len = 0;
+ while ((c = getescc('"')) >= 0) {
+ /* +1 to reserve space for a trailing NUL character */
+ if (len + 1 == max)
+ s = xrealloc(s, max *= 2);
+ s[len++] = (char)c;
+ }
+ s[len] = '\0';
+ if (c == -2)
+ /* unterminated string constant */
+ error(258);
+
+ strg = xcalloc(1, sizeof (strg_t));
+ strg->st_tspec = CHAR;
+ strg->st_len = len;
+ strg->st_cp = s;
+
+ yylval.y_strg = strg;
+ return (T_STRING);
+}
+
+static int
+wcstrg()
+{
+ char *s;
+ int c, i, n, wi;
+ size_t len, max, wlen;
+ wchar_t *ws;
+ strg_t *strg;
+
+ s = xmalloc(max = 64);
+ len = 0;
+ while ((c = getescc('"')) >= 0) {
+ /* +1 to save space for a trailing NUL character */
+ if (len + 1 >= max)
+ s = xrealloc(s, max *= 2);
+ s[len++] = (char)c;
+ }
+ s[len] = '\0';
+ if (c == -2)
+ /* unterminated string constant */
+ error(258);
+
+ /* get length of wide character string */
+ (void)mblen(NULL, 0);
+ for (i = 0, wlen = 0; i < len; i += n, wlen++) {
+ if ((n = mblen(&s[i], MB_CUR_MAX)) == -1) {
+ /* invalid multibyte character */
+ error(291);
+ break;
+ }
+ if (n == 0)
+ n = 1;
+ }
+
+ ws = xmalloc((wlen + 1) * sizeof (wchar_t));
+
+ /* convert from multibyte to wide char */
+ (void)mbtowc(NULL, NULL, 0);
+ for (i = 0, wi = 0; i < len; i += n, wi++) {
+ if ((n = mbtowc(&ws[wi], &s[i], MB_CUR_MAX)) == -1)
+ break;
+ if (n == 0)
+ n = 1;
+ }
+ ws[wi] = 0;
+ free(s);
+
+ strg = xcalloc(1, sizeof (strg_t));
+ strg->st_tspec = WCHAR;
+ strg->st_len = wlen;
+ strg->st_wcp = ws;
+
+ yylval.y_strg = strg;
+ return (T_STRING);
+}
+
+/*
+ * As noted above the scanner does not create new symbol table entries
+ * for symbols it cannot find in the symbol table. This is to avoid
+ * putting undeclared symbols into the symbol table if a syntax error
+ * occurs.
+ *
+ * getsym() is called as soon as it is probably ok to put the symbol to
+ * the symbol table. This does not mean that it is not possible that
+ * symbols are put to the symbol table which are than not completely
+ * declared due to syntax errors. To avoid too many problems in this
+ * case symbols get type int in getsym().
+ *
+ * XXX calls to getsym() should be delayed until decl1*() is called
+ */
+sym_t *
+getsym(sb)
+ sbuf_t *sb;
+{
+ dinfo_t *di;
+ char *s;
+ sym_t *sym;
+
+ sym = sb->sb_sym;
+
+ /*
+ * During member declaration it is possible that name() looked
+ * for symbols of type FVFT, although it should have looked for
+ * symbols of type FTAG. Same can happen for labels. Both cases
+ * are compensated here.
+ */
+ if (symtyp == FMOS || symtyp == FLAB) {
+ if (sym == NULL || sym->s_kind == FVFT)
+ sym = search(sb);
+ }
+
+ if (sym != NULL) {
+ if (sym->s_kind != symtyp)
+ lerror("storesym() 1");
+ symtyp = FVFT;
+ freesb(sb);
+ return (sym);
+ }
+
+ /* create a new symbol table entry */
+
+ /* labels must always be allocated at level 1 (outhermost block) */
+ if (symtyp == FLAB) {
+ sym = getlblk(1, sizeof (sym_t));
+ s = getlblk(1, sb->sb_len + 1);
+ (void)memcpy(s, sb->sb_name, sb->sb_len + 1);
+ sym->s_name = s;
+ sym->s_blklev = 1;
+ di = dcs;
+ while (di->d_nxt != NULL && di->d_nxt->d_nxt != NULL)
+ di = di->d_nxt;
+ if (di->d_ctx != AUTO)
+ lerror("storesym() 2");
+ } else {
+ sym = getblk(sizeof (sym_t));
+ sym->s_name = sb->sb_name;
+ sym->s_blklev = blklev;
+ di = dcs;
+ }
+
+ STRUCT_ASSIGN(sym->s_dpos, curr_pos);
+ if ((sym->s_kind = symtyp) != FLAB)
+ sym->s_type = gettyp(INT);
+
+ symtyp = FVFT;
+
+ if ((sym->s_link = symtab[sb->sb_hash]) != NULL)
+ symtab[sb->sb_hash]->s_rlink = &sym->s_link;
+ (symtab[sb->sb_hash] = sym)->s_rlink = &symtab[sb->sb_hash];
+
+ *di->d_ldlsym = sym;
+ di->d_ldlsym = &sym->s_dlnxt;
+
+ freesb(sb);
+ return (sym);
+}
+
+/*
+ * Remove a symbol forever from the symbol table. s_blklev
+ * is set to -1 to avoid that the symbol will later be put
+ * back to the symbol table.
+ */
+void
+rmsym(sym)
+ sym_t *sym;
+{
+ if ((*sym->s_rlink = sym->s_link) != NULL)
+ sym->s_link->s_rlink = sym->s_rlink;
+ sym->s_blklev = -1;
+ sym->s_link = NULL;
+}
+
+/*
+ * Remove a list of symbols declared at one level from the symbol
+ * table.
+ */
+void
+rmsyms(syms)
+ sym_t *syms;
+{
+ sym_t *sym;
+
+ for (sym = syms; sym != NULL; sym = sym->s_dlnxt) {
+ if (sym->s_blklev != -1) {
+ if ((*sym->s_rlink = sym->s_link) != NULL)
+ sym->s_link->s_rlink = sym->s_rlink;
+ sym->s_link = NULL;
+ sym->s_rlink = NULL;
+ }
+ }
+}
+
+/*
+ * Put a symbol into the symbol table
+ */
+void
+inssym(bl, sym)
+ int bl;
+ sym_t *sym;
+{
+ int h;
+
+ h = hash(sym->s_name);
+ if ((sym->s_link = symtab[h]) != NULL)
+ symtab[h]->s_rlink = &sym->s_link;
+ (symtab[h] = sym)->s_rlink = &symtab[h];
+ sym->s_blklev = bl;
+ if (sym->s_link != NULL && sym->s_blklev < sym->s_link->s_blklev)
+ lerror("inssym()");
+}
+
+/*
+ * Called at level 0 after syntax errors
+ * Removes all symbols which are not declared at level 0 from the
+ * symbol table. Also frees all memory which is not associated with
+ * level 0.
+ */
+void
+cleanup()
+{
+ sym_t *sym, *nsym;
+ int i;
+
+ for (i = 0; i < HSHSIZ1; i++) {
+ for (sym = symtab[i]; sym != NULL; sym = nsym) {
+ nsym = sym->s_link;
+ if (sym->s_blklev >= 1) {
+ if ((*sym->s_rlink = nsym) != NULL)
+ nsym->s_rlink = sym->s_rlink;
+ }
+ }
+ }
+
+ for (i = mblklev; i > 0; i--)
+ freelblk(i);
+}
+
+/*
+ * Create a new symbol with the name of an existing symbol.
+ */
+sym_t *
+pushdown(sym)
+ sym_t *sym;
+{
+ int h;
+ sym_t *nsym;
+
+ h = hash(sym->s_name);
+ nsym = getblk(sizeof (sym_t));
+ if (sym->s_blklev > blklev)
+ lerror("pushdown()");
+ nsym->s_name = sym->s_name;
+ STRUCT_ASSIGN(nsym->s_dpos, curr_pos);
+ nsym->s_kind = sym->s_kind;
+ nsym->s_blklev = blklev;
+
+ if ((nsym->s_link = symtab[h]) != NULL)
+ symtab[h]->s_rlink = &nsym->s_link;
+ (symtab[h] = nsym)->s_rlink = &symtab[h];
+
+ *dcs->d_ldlsym = nsym;
+ dcs->d_ldlsym = &nsym->s_dlnxt;
+
+ return (nsym);
+}
+
+/*
+ * Free any dynamically allocated memory referenced by
+ * the value stack or yylval.
+ * The type of information in yylval is described by tok.
+ */
+void
+freeyyv(sp, tok)
+ void *sp;
+ int tok;
+{
+ if (tok == T_NAME || tok == T_TYPENAME) {
+ sbuf_t *sb = *(sbuf_t **)sp;
+ freesb(sb);
+ } else if (tok == T_CON) {
+ val_t *val = *(val_t **)sp;
+ free(val);
+ } else if (tok == T_STRING) {
+ strg_t *strg = *(strg_t **)sp;
+ if (strg->st_tspec == CHAR) {
+ free(strg->st_cp);
+ } else if (strg->st_tspec == WCHAR) {
+ free(strg->st_wcp);
+ } else {
+ lerror("fryylv() 1");
+ }
+ free(strg);
+ }
+}
diff --git a/usr.bin/xlint/lint1/tree.c b/usr.bin/xlint/lint1/tree.c
new file mode 100644
index 0000000..525e407
--- /dev/null
+++ b/usr.bin/xlint/lint1/tree.c
@@ -0,0 +1,3924 @@
+/* $NetBSD: tree.c,v 1.12 1995/10/02 17:37:57 jpo Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Jochen Pohl
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jochen Pohl for
+ * The NetBSD Project.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: tree.c,v 1.12 1995/10/02 17:37:57 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+
+#include "lint1.h"
+#include "y.tab.h"
+
+/* Various flags for each operator. */
+static mod_t modtab[NOPS];
+
+static tnode_t *getinode __P((tspec_t, quad_t));
+static void ptrcmpok __P((op_t, tnode_t *, tnode_t *));
+static int asgntypok __P((op_t, int, tnode_t *, tnode_t *));
+static void chkbeop __P((op_t, tnode_t *, tnode_t *));
+static void chkeop2 __P((op_t, int, tnode_t *, tnode_t *));
+static void chkeop1 __P((op_t, int, tnode_t *, tnode_t *));
+static tnode_t *mktnode __P((op_t, type_t *, tnode_t *, tnode_t *));
+static void balance __P((op_t, tnode_t **, tnode_t **));
+static void incompat __P((op_t, tspec_t, tspec_t));
+static void illptrc __P((mod_t *, type_t *, type_t *));
+static void mrgqual __P((type_t **, type_t *, type_t *));
+static int conmemb __P((type_t *));
+static void ptconv __P((int, tspec_t, tspec_t, type_t *, tnode_t *));
+static void iiconv __P((op_t, int, tspec_t, tspec_t, type_t *, tnode_t *));
+static void piconv __P((op_t, tspec_t, type_t *, tnode_t *));
+static void ppconv __P((op_t, tnode_t *, type_t *));
+static tnode_t *bldstr __P((op_t, tnode_t *, tnode_t *));
+static tnode_t *bldincdec __P((op_t, tnode_t *));
+static tnode_t *bldamper __P((tnode_t *, int));
+static tnode_t *bldplmi __P((op_t, tnode_t *, tnode_t *));
+static tnode_t *bldshft __P((op_t, tnode_t *, tnode_t *));
+static tnode_t *bldcol __P((tnode_t *, tnode_t *));
+static tnode_t *bldasgn __P((op_t, tnode_t *, tnode_t *));
+static tnode_t *plength __P((type_t *));
+static tnode_t *fold __P((tnode_t *));
+static tnode_t *foldtst __P((tnode_t *));
+static tnode_t *foldflt __P((tnode_t *));
+static tnode_t *chkfarg __P((type_t *, tnode_t *));
+static tnode_t *parg __P((int, type_t *, tnode_t *));
+static void nulleff __P((tnode_t *));
+static void displexpr __P((tnode_t *, int));
+static void chkaidx __P((tnode_t *, int));
+static void chkcomp __P((op_t, tnode_t *, tnode_t *));
+static void precconf __P((tnode_t *));
+
+/*
+ * Initialize mods of operators.
+ */
+void
+initmtab()
+{
+ static struct {
+ op_t op;
+ mod_t m;
+ } imods[] = {
+ { ARROW, { 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
+ "->" } },
+ { POINT, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "." } },
+ { NOT, { 0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,
+ "!" } },
+ { COMPL, { 0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,1,1,
+ "~" } },
+ { INCBEF, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "prefix++" } },
+ { DECBEF, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "prefix--" } },
+ { INCAFT, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "postfix++" } },
+ { DECAFT, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "postfix--" } },
+ { UPLUS, { 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,
+ "unary +" } },
+ { UMINUS, { 0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,1,1,
+ "unary -" } },
+ { STAR, { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
+ "unary *" } },
+ { AMPER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "unary &" } },
+ { MULT, { 1,0,0,0,1,1,1,0,1,0,0,1,0,0,0,1,1,
+ "*" } },
+ { DIV, { 1,0,0,0,1,1,1,0,1,0,1,1,0,0,0,1,1,
+ "/" } },
+ { MOD, { 1,0,1,0,0,1,1,0,1,0,1,1,0,0,0,1,1,
+ "%" } },
+ { PLUS, { 1,0,0,1,0,1,1,0,1,0,0,0,0,0,0,1,0,
+ "+" } },
+ { MINUS, { 1,0,0,1,0,1,1,0,1,0,0,0,0,0,0,1,0,
+ "-" } },
+ { SHL, { 1,0,1,0,0,1,1,0,0,0,0,0,1,0,0,1,1,
+ "<<" } },
+ { SHR, { 1,0,1,0,0,1,1,0,0,0,1,0,1,0,0,1,1,
+ ">>" } },
+ { LT, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,
+ "<" } },
+ { LE, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,
+ "<=" } },
+ { GT, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,
+ ">" } },
+ { GE, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,
+ ">=" } },
+ { EQ, { 1,1,0,1,0,1,1,0,1,0,0,0,0,1,1,0,1,
+ "==" } },
+ { NE, { 1,1,0,1,0,1,1,0,1,0,0,0,0,1,1,0,1,
+ "!=" } },
+ { AND, { 1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,
+ "&" } },
+ { XOR, { 1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,
+ "^" } },
+ { OR, { 1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,
+ "|" } },
+ { LOGAND, { 1,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,
+ "&&" } },
+ { LOGOR, { 1,1,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,
+ "||" } },
+ { QUEST, { 1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,
+ "?" } },
+ { COLON, { 1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,
+ ":" } },
+ { ASSIGN, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,
+ "=" } },
+ { MULASS, { 1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,
+ "*=" } },
+ { DIVASS, { 1,0,0,0,1,0,0,0,0,1,0,1,0,0,0,1,0,
+ "/=" } },
+ { MODASS, { 1,0,1,0,0,0,0,0,0,1,0,1,0,0,0,1,0,
+ "%=" } },
+ { ADDASS, { 1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "+=" } },
+ { SUBASS, { 1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "-=" } },
+ { SHLASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "<<=" } },
+ { SHRASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ ">>=" } },
+ { ANDASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "&=" } },
+ { XORASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "^=" } },
+ { ORASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "|=" } },
+ { NAME, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "NAME" } },
+ { CON, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "CON" } },
+ { STRING, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "STRING" } },
+ { FSEL, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "FSEL" } },
+ { CALL, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
+ "CALL" } },
+ { COMMA, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
+ "," } },
+ { CVT, { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
+ "CVT" } },
+ { ICALL, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
+ "ICALL" } },
+ { LOAD, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "LOAD" } },
+ { PUSH, { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
+ "PUSH" } },
+ { RETURN, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,
+ "RETURN" } },
+ { INIT, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
+ "INIT" } },
+ { FARG, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
+ "FARG" } },
+ { NOOP }
+ };
+ int i;
+
+ for (i = 0; imods[i].op != NOOP; i++)
+ STRUCT_ASSIGN(modtab[imods[i].op], imods[i].m);
+}
+
+/*
+ * Increase degree of reference.
+ * This is most often used to change type "T" in type "pointer to T".
+ */
+type_t *
+incref(tp, t)
+ type_t *tp;
+ tspec_t t;
+{
+ type_t *tp2;
+
+ tp2 = getblk(sizeof (type_t));
+ tp2->t_tspec = t;
+ tp2->t_subt = tp;
+ return (tp2);
+}
+
+/*
+ * same for use in expressions
+ */
+type_t *
+tincref(tp, t)
+ type_t *tp;
+ tspec_t t;
+{
+ type_t *tp2;
+
+ tp2 = tgetblk(sizeof (type_t));
+ tp2->t_tspec = t;
+ tp2->t_subt = tp;
+ return (tp2);
+}
+
+/*
+ * Create a node for a constant.
+ */
+tnode_t *
+getcnode(tp, v)
+ type_t *tp;
+ val_t *v;
+{
+ tnode_t *n;
+
+ n = getnode();
+ n->tn_op = CON;
+ n->tn_type = tp;
+ n->tn_val = tgetblk(sizeof (val_t));
+ n->tn_val->v_tspec = tp->t_tspec;
+ n->tn_val->v_ansiu = v->v_ansiu;
+ n->tn_val->v_u = v->v_u;
+ free(v);
+ return (n);
+}
+
+/*
+ * Create a node for a integer constant.
+ */
+static tnode_t *
+getinode(t, q)
+ tspec_t t;
+ quad_t q;
+{
+ tnode_t *n;
+
+ n = getnode();
+ n->tn_op = CON;
+ n->tn_type = gettyp(t);
+ n->tn_val = tgetblk(sizeof (val_t));
+ n->tn_val->v_tspec = t;
+ n->tn_val->v_quad = q;
+ return (n);
+}
+
+/*
+ * Create a node for a name (symbol table entry).
+ * ntok is the token which follows the name.
+ */
+tnode_t *
+getnnode(sym, ntok)
+ sym_t *sym;
+ int ntok;
+{
+ tnode_t *n;
+
+ if (sym->s_scl == NOSCL) {
+ sym->s_scl = EXTERN;
+ sym->s_def = DECL;
+ if (ntok == T_LPARN) {
+ if (sflag) {
+ /* function implicitly declared to ... */
+ warning(215);
+ }
+ /*
+ * XXX if tflag is set the symbol should be
+ * exported to level 0
+ */
+ sym->s_type = incref(sym->s_type, FUNC);
+ } else {
+ /* %s undefined */
+ error(99, sym->s_name);
+ }
+ }
+
+ if (sym->s_kind != FVFT && sym->s_kind != FMOS)
+ lerror("getnnode() 1");
+
+ n = getnode();
+ n->tn_type = sym->s_type;
+ if (sym->s_scl != ENUMCON) {
+ n->tn_op = NAME;
+ n->tn_sym = sym;
+ if (sym->s_kind == FVFT && sym->s_type->t_tspec != FUNC)
+ n->tn_lvalue = 1;
+ } else {
+ n->tn_op = CON;
+ n->tn_val = tgetblk(sizeof (val_t));
+ *n->tn_val = sym->s_value;
+ }
+
+ return (n);
+}
+
+/*
+ * Create a node for a string.
+ */
+tnode_t *
+getsnode(strg)
+ strg_t *strg;
+{
+ size_t len;
+ tnode_t *n;
+
+ len = strg->st_len;
+
+ n = getnode();
+
+ n->tn_op = STRING;
+ n->tn_type = tincref(gettyp(strg->st_tspec), ARRAY);
+ n->tn_type->t_dim = len + 1;
+ n->tn_lvalue = 1;
+
+ n->tn_strg = tgetblk(sizeof (strg_t));
+ n->tn_strg->st_tspec = strg->st_tspec;
+ n->tn_strg->st_len = len;
+
+ if (strg->st_tspec == CHAR) {
+ n->tn_strg->st_cp = tgetblk(len + 1);
+ (void)memcpy(n->tn_strg->st_cp, strg->st_cp, len + 1);
+ free(strg->st_cp);
+ } else {
+ n->tn_strg->st_wcp = tgetblk((len + 1) * sizeof (wchar_t));
+ (void)memcpy(n->tn_strg->st_wcp, strg->st_wcp,
+ (len + 1) * sizeof (wchar_t));
+ free(strg->st_wcp);
+ }
+ free(strg);
+
+ return (n);
+}
+
+/*
+ * Returns a symbol which has the same name as the msym argument and is a
+ * member of the struct or union specified by the tn argument.
+ */
+sym_t *
+strmemb(tn, op, msym)
+ tnode_t *tn;
+ op_t op;
+ sym_t *msym;
+{
+ str_t *str;
+ type_t *tp;
+ sym_t *sym, *csym;
+ int eq;
+ tspec_t t;
+
+ /*
+ * Remove the member if it was unknown until now (Which means
+ * that no defined struct or union has a member with the same name).
+ */
+ if (msym->s_scl == NOSCL) {
+ /* undefined struct/union member: %s */
+ error(101, msym->s_name);
+ rmsym(msym);
+ msym->s_kind = FMOS;
+ msym->s_scl = MOS;
+ msym->s_styp = tgetblk(sizeof (str_t));
+ msym->s_styp->stag = tgetblk(sizeof (sym_t));
+ msym->s_styp->stag->s_name = unnamed;
+ msym->s_value.v_tspec = INT;
+ return (msym);
+ }
+
+ /* Set str to the tag of which msym is expected to be a member. */
+ str = NULL;
+ t = (tp = tn->tn_type)->t_tspec;
+ if (op == POINT) {
+ if (t == STRUCT || t == UNION)
+ str = tp->t_str;
+ } else if (op == ARROW && t == PTR) {
+ t = (tp = tp->t_subt)->t_tspec;
+ if (t == STRUCT || t == UNION)
+ str = tp->t_str;
+ }
+
+ /*
+ * If this struct/union has a member with the name of msym, return
+ * return this it.
+ */
+ if (str != NULL) {
+ for (sym = msym; sym != NULL; sym = sym->s_link) {
+ if (sym->s_scl != MOS && sym->s_scl != MOU)
+ continue;
+ if (sym->s_styp != str)
+ continue;
+ if (strcmp(sym->s_name, msym->s_name) != 0)
+ continue;
+ return (sym);
+ }
+ }
+
+ /*
+ * Set eq to 0 if there are struct/union members with the same name
+ * and different types and/or offsets.
+ */
+ eq = 1;
+ for (csym = msym; csym != NULL; csym = csym->s_link) {
+ if (csym->s_scl != MOS && csym->s_scl != MOU)
+ continue;
+ if (strcmp(msym->s_name, csym->s_name) != 0)
+ continue;
+ for (sym = csym->s_link ; sym != NULL; sym = sym->s_link) {
+ int w;
+
+ if (sym->s_scl != MOS && sym->s_scl != MOU)
+ continue;
+ if (strcmp(csym->s_name, sym->s_name) != 0)
+ continue;
+ if (csym->s_value.v_quad != sym->s_value.v_quad) {
+ eq = 0;
+ break;
+ }
+ w = 0;
+ eq = eqtype(csym->s_type, sym->s_type, 0, 0, &w) && !w;
+ if (!eq)
+ break;
+ if (csym->s_field != sym->s_field) {
+ eq = 0;
+ break;
+ }
+ if (csym->s_field) {
+ type_t *tp1, *tp2;
+
+ tp1 = csym->s_type;
+ tp2 = sym->s_type;
+ if (tp1->t_flen != tp2->t_flen) {
+ eq = 0;
+ break;
+ }
+ if (tp1->t_foffs != tp2->t_foffs) {
+ eq = 0;
+ break;
+ }
+ }
+ }
+ if (!eq)
+ break;
+ }
+
+ /*
+ * Now handle the case in which the left operand refers really
+ * to a struct/union, but the right operand is not member of it.
+ */
+ if (str != NULL) {
+ /* illegal member use: %s */
+ if (eq && tflag) {
+ warning(102, msym->s_name);
+ } else {
+ error(102, msym->s_name);
+ }
+ return (msym);
+ }
+
+ /*
+ * Now the left operand of ARROW does not point to a struct/union
+ * or the left operand of POINT is no struct/union.
+ */
+ if (eq) {
+ if (op == POINT) {
+ /* left operand of "." must be struct/union object */
+ if (tflag) {
+ warning(103);
+ } else {
+ error(103);
+ }
+ } else {
+ /* left operand of "->" must be pointer to ... */
+ if (tflag && tn->tn_type->t_tspec == PTR) {
+ warning(104);
+ } else {
+ error(104);
+ }
+ }
+ } else {
+ if (tflag) {
+ /* non-unique member requires struct/union %s */
+ error(105, op == POINT ? "object" : "pointer");
+ } else {
+ /* unacceptable operand of %s */
+ error(111, modtab[op].m_name);
+ }
+ }
+
+ return (msym);
+}
+
+/*
+ * Create a tree node. Called for most operands except function calls,
+ * sizeof and casts.
+ *
+ * op operator
+ * ln left operand
+ * rn if not NULL, right operand
+ */
+tnode_t *
+build(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ mod_t *mp;
+ tnode_t *ntn;
+ type_t *rtp;
+
+ mp = &modtab[op];
+
+ /* If there was an error in one of the operands, return. */
+ if (ln == NULL || (mp->m_binary && rn == NULL))
+ return (NULL);
+
+ /*
+ * Apply class conversions to the left operand, but only if its
+ * value is needed or it is compaired with null.
+ */
+ if (mp->m_vctx || mp->m_tctx)
+ ln = cconv(ln);
+ /*
+ * The right operand is almost always in a test or value context,
+ * except if it is a struct or union member.
+ */
+ if (mp->m_binary && op != ARROW && op != POINT)
+ rn = cconv(rn);
+
+ /*
+ * Print some warnings for comparisions of unsigned values with
+ * constants lower than or equal to null. This must be done
+ * before promote() because otherwise unsigned char and unsigned
+ * short would be promoted to int. Also types are tested to be
+ * CHAR, which would also become int.
+ */
+ if (mp->m_comp)
+ chkcomp(op, ln, rn);
+
+ /*
+ * Promote the left operand if it is in a test or value context
+ */
+ if (mp->m_vctx || mp->m_tctx)
+ ln = promote(op, 0, ln);
+ /*
+ * Promote the right operand, but only if it is no struct or
+ * union member, or if it is not to be assigned to the left operand
+ */
+ if (mp->m_binary && op != ARROW && op != POINT &&
+ op != ASSIGN && op != RETURN) {
+ rn = promote(op, 0, rn);
+ }
+
+ /*
+ * If the result of the operation is different for signed or
+ * unsigned operands and one of the operands is signed only in
+ * ANSI C, print a warning.
+ */
+ if (mp->m_tlansiu && ln->tn_op == CON && ln->tn_val->v_ansiu) {
+ /* ANSI C treats constant as unsigned, op %s */
+ warning(218, mp->m_name);
+ ln->tn_val->v_ansiu = 0;
+ }
+ if (mp->m_transiu && rn->tn_op == CON && rn->tn_val->v_ansiu) {
+ /* ANSI C treats constant as unsigned, op %s */
+ warning(218, mp->m_name);
+ rn->tn_val->v_ansiu = 0;
+ }
+
+ /* Make sure both operands are of the same type */
+ if (mp->m_balance || (tflag && (op == SHL || op == SHR)))
+ balance(op, &ln, &rn);
+
+ /*
+ * Check types for compatibility with the operation and mutual
+ * compatibility. Return if there are serios problems.
+ */
+ if (!typeok(op, 0, ln, rn))
+ return (NULL);
+
+ /* And now create the node. */
+ switch (op) {
+ case POINT:
+ case ARROW:
+ ntn = bldstr(op, ln, rn);
+ break;
+ case INCAFT:
+ case DECAFT:
+ case INCBEF:
+ case DECBEF:
+ ntn = bldincdec(op, ln);
+ break;
+ case AMPER:
+ ntn = bldamper(ln, 0);
+ break;
+ case STAR:
+ ntn = mktnode(STAR, ln->tn_type->t_subt, ln, NULL);
+ break;
+ case PLUS:
+ case MINUS:
+ ntn = bldplmi(op, ln, rn);
+ break;
+ case SHL:
+ case SHR:
+ ntn = bldshft(op, ln, rn);
+ break;
+ case COLON:
+ ntn = bldcol(ln, rn);
+ break;
+ case ASSIGN:
+ case MULASS:
+ case DIVASS:
+ case MODASS:
+ case ADDASS:
+ case SUBASS:
+ case SHLASS:
+ case SHRASS:
+ case ANDASS:
+ case XORASS:
+ case ORASS:
+ case RETURN:
+ ntn = bldasgn(op, ln, rn);
+ break;
+ case COMMA:
+ case QUEST:
+ ntn = mktnode(op, rn->tn_type, ln, rn);
+ break;
+ default:
+ rtp = mp->m_logop ? gettyp(INT) : ln->tn_type;
+ if (!mp->m_binary && rn != NULL)
+ lerror("build() 1");
+ ntn = mktnode(op, rtp, ln, rn);
+ break;
+ }
+
+ /* Return if an error occured. */
+ if (ntn == NULL)
+ return (NULL);
+
+ /* Print a warning if precedence confusion is possible */
+ if (mp->m_tpconf)
+ precconf(ntn);
+
+ /*
+ * Print a warning if one of the operands is in a context where
+ * it is compared with null and if this operand is a constant.
+ */
+ if (mp->m_tctx) {
+ if (ln->tn_op == CON ||
+ ((mp->m_binary && op != QUEST) && rn->tn_op == CON)) {
+ if (hflag && !ccflg)
+ /* constant in conditional context */
+ warning(161);
+ }
+ }
+
+ /* Fold if the operator requires it */
+ if (mp->m_fold) {
+ if (ln->tn_op == CON && (!mp->m_binary || rn->tn_op == CON)) {
+ if (mp->m_tctx) {
+ ntn = foldtst(ntn);
+ } else if (isftyp(ntn->tn_type->t_tspec)) {
+ ntn = foldflt(ntn);
+ } else {
+ ntn = fold(ntn);
+ }
+ } else if (op == QUEST && ln->tn_op == CON) {
+ ntn = ln->tn_val->v_quad ? rn->tn_left : rn->tn_right;
+ }
+ }
+
+ return (ntn);
+}
+
+/*
+ * Perform class conversions.
+ *
+ * Arrays of type T are converted into pointers to type T.
+ * Functions are converted to pointers to functions.
+ * Lvalues are converted to rvalues.
+ */
+tnode_t *
+cconv(tn)
+ tnode_t *tn;
+{
+ type_t *tp;
+
+ /*
+ * Array-lvalue (array of type T) is converted into rvalue
+ * (pointer to type T)
+ */
+ if (tn->tn_type->t_tspec == ARRAY) {
+ if (!tn->tn_lvalue) {
+ /* %soperand of '%s' must be lvalue */
+ /* XXX print correct operator */
+ (void)gnuism(114, "", modtab[AMPER].m_name);
+ }
+ tn = mktnode(AMPER, tincref(tn->tn_type->t_subt, PTR),
+ tn, NULL);
+ }
+
+ /*
+ * Expression of type function (function with return value of type T)
+ * in rvalue-expression (pointer to function with return value
+ * of type T)
+ */
+ if (tn->tn_type->t_tspec == FUNC)
+ tn = bldamper(tn, 1);
+
+ /* lvalue to rvalue */
+ if (tn->tn_lvalue) {
+ tp = tduptyp(tn->tn_type);
+ tp->t_const = tp->t_volatile = 0;
+ tn = mktnode(LOAD, tp, tn, NULL);
+ }
+
+ return (tn);
+}
+
+/*
+ * Perform most type checks. First the types are checked using
+ * informations from modtab[]. After that it is done by hand for
+ * more complicated operators and type combinations.
+ *
+ * If the types are ok, typeok() returns 1, otherwise 0.
+ */
+int
+typeok(op, arg, ln, rn)
+ op_t op;
+ int arg;
+ tnode_t *ln, *rn;
+{
+ mod_t *mp;
+ tspec_t lt, rt, lst, rst, olt, ort;
+ type_t *ltp, *rtp, *lstp, *rstp;
+ tnode_t *tn;
+
+ mp = &modtab[op];
+
+ if ((lt = (ltp = ln->tn_type)->t_tspec) == PTR)
+ lst = (lstp = ltp->t_subt)->t_tspec;
+ if (mp->m_binary) {
+ if ((rt = (rtp = rn->tn_type)->t_tspec) == PTR)
+ rst = (rstp = rtp->t_subt)->t_tspec;
+ }
+
+ if (mp->m_rqint) {
+ /* integertypes required */
+ if (!isityp(lt) || (mp->m_binary && !isityp(rt))) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ } else if (mp->m_rqsclt) {
+ /* scalar types required */
+ if (!issclt(lt) || (mp->m_binary && !issclt(rt))) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ } else if (mp->m_rqatyp) {
+ /* arithmetic types required */
+ if (!isatyp(lt) || (mp->m_binary && !isatyp(rt))) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ }
+
+ if (op == SHL || op == SHR || op == SHLASS || op == SHRASS) {
+ /*
+ * For these operations we need the types before promotion
+ * and balancing.
+ */
+ for (tn=ln; tn->tn_op==CVT && !tn->tn_cast; tn=tn->tn_left) ;
+ olt = tn->tn_type->t_tspec;
+ for (tn=rn; tn->tn_op==CVT && !tn->tn_cast; tn=tn->tn_left) ;
+ ort = tn->tn_type->t_tspec;
+ }
+
+ switch (op) {
+ case POINT:
+ /*
+ * Most errors required by ANSI C are reported in strmemb().
+ * Here we only must check for totaly wrong things.
+ */
+ if (lt == FUNC || lt == VOID || ltp->t_isfield ||
+ ((lt != STRUCT && lt != UNION) && !ln->tn_lvalue)) {
+ /* Without tflag we got already an error */
+ if (tflag)
+ /* unacceptable operand of %s */
+ error(111, mp->m_name);
+ return (0);
+ }
+ /* Now we have an object we can create a pointer to */
+ break;
+ case ARROW:
+ if (lt != PTR && !(tflag && isityp(lt))) {
+ /* Without tflag we got already an error */
+ if (tflag)
+ /* unacceptabel operand of %s */
+ error(111, mp->m_name);
+ return (0);
+ }
+ break;
+ case INCAFT:
+ case DECAFT:
+ case INCBEF:
+ case DECBEF:
+ /* operands have scalar types (checked above) */
+ if (!ln->tn_lvalue) {
+ if (ln->tn_op == CVT && ln->tn_cast &&
+ ln->tn_left->tn_op == LOAD) {
+ /* a cast does not yield an lvalue */
+ error(163);
+ }
+ /* %soperand of %s must be lvalue */
+ error(114, "", mp->m_name);
+ return (0);
+ } else if (ltp->t_const) {
+ /* %soperand of %s must be modifiable lvalue */
+ if (!tflag)
+ warning(115, "", mp->m_name);
+ }
+ break;
+ case AMPER:
+ if (lt == ARRAY || lt == FUNC) {
+ /* ok, a warning comes later (in bldamper()) */
+ } else if (!ln->tn_lvalue) {
+ if (ln->tn_op == CVT && ln->tn_cast &&
+ ln->tn_left->tn_op == LOAD) {
+ /* a cast does not yield an lvalue */
+ error(163);
+ }
+ /* %soperand of %s must be lvalue */
+ error(114, "", mp->m_name);
+ return (0);
+ } else if (issclt(lt)) {
+ if (ltp->t_isfield) {
+ /* cannot take address of bit-field */
+ error(112);
+ return (0);
+ }
+ } else if (lt != STRUCT && lt != UNION) {
+ /* unacceptable operand of %s */
+ error(111, mp->m_name);
+ return (0);
+ }
+ if (ln->tn_op == NAME && ln->tn_sym->s_reg) {
+ /* cannot take address of register %s */
+ error(113, ln->tn_sym->s_name);
+ return (0);
+ }
+ break;
+ case STAR:
+ /* until now there were no type checks for this operator */
+ if (lt != PTR) {
+ /* cannot dereference non-pointer type */
+ error(96);
+ return (0);
+ }
+ break;
+ case PLUS:
+ /* operands have scalar types (checked above) */
+ if ((lt == PTR && !isityp(rt)) || (rt == PTR && !isityp(lt))) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ break;
+ case MINUS:
+ /* operands have scalar types (checked above) */
+ if (lt == PTR && (!isityp(rt) && rt != PTR)) {
+ incompat(op, lt, rt);
+ return (0);
+ } else if (rt == PTR && lt != PTR) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ if (lt == PTR && rt == PTR) {
+ if (!eqtype(lstp, rstp, 1, 0, NULL)) {
+ /* illegal pointer subtraction */
+ error(116);
+ }
+ }
+ break;
+ case SHR:
+ /* operands have integer types (checked above) */
+ if (pflag && !isutyp(lt)) {
+ /*
+ * The left operand is signed. This means that
+ * the operation is (possibly) nonportable.
+ */
+ /* bitwise operation on signed value nonportable */
+ if (ln->tn_op != CON) {
+ /* possibly nonportable */
+ warning(117);
+ } else if (ln->tn_val->v_quad < 0) {
+ warning(120);
+ }
+ } else if (!tflag && !sflag && !isutyp(olt) && isutyp(ort)) {
+ /*
+ * The left operand would become unsigned in
+ * traditional C.
+ */
+ if (hflag &&
+ (ln->tn_op != CON || ln->tn_val->v_quad < 0)) {
+ /* semantics of %s change in ANSI C; use ... */
+ warning(118, mp->m_name);
+ }
+ } else if (!tflag && !sflag && !isutyp(olt) && !isutyp(ort) &&
+ psize(lt) < psize(rt)) {
+ /*
+ * In traditional C the left operand would be extended,
+ * possibly with 1, and then shifted.
+ */
+ if (hflag &&
+ (ln->tn_op != CON || ln->tn_val->v_quad < 0)) {
+ /* semantics of %s change in ANSI C; use ... */
+ warning(118, mp->m_name);
+ }
+ }
+ goto shift;
+ case SHL:
+ /*
+ * ANSI C does not perform balancing for shift operations,
+ * but traditional C does. If the width of the right operand
+ * is greather than the width of the left operand, than in
+ * traditional C the left operand would be extendet to the
+ * width of the right operand. For SHL this may result in
+ * different results.
+ */
+ if (psize(lt) < psize(rt)) {
+ /*
+ * XXX If both operands are constant make sure
+ * that there is really a differencs between
+ * ANSI C and traditional C.
+ */
+ if (hflag)
+ /* semantics of %s change in ANSI C; use ... */
+ warning(118, mp->m_name);
+ }
+ shift:
+ if (rn->tn_op == CON) {
+ if (!isutyp(rt) && rn->tn_val->v_quad < 0) {
+ /* negative shift */
+ warning(121);
+ } else if ((u_quad_t)rn->tn_val->v_quad == size(lt)) {
+ /* shift equal to size fo object */
+ warning(267);
+ } else if ((u_quad_t)rn->tn_val->v_quad > size(lt)) {
+ /* shift greater than size of object */
+ warning(122);
+ }
+ }
+ break;
+ case EQ:
+ case NE:
+ /*
+ * Accept some things which are allowed with EQ and NE,
+ * but not with ordered comparisions.
+ */
+ if (lt == PTR && ((rt == PTR && rst == VOID) || isityp(rt))) {
+ if (rn->tn_op == CON && rn->tn_val->v_quad == 0)
+ break;
+ }
+ if (rt == PTR && ((lt == PTR && lst == VOID) || isityp(lt))) {
+ if (ln->tn_op == CON && ln->tn_val->v_quad == 0)
+ break;
+ }
+ /* FALLTHROUGH */
+ case LT:
+ case GT:
+ case LE:
+ case GE:
+ if ((lt == PTR || rt == PTR) && lt != rt) {
+ if (isityp(lt) || isityp(rt)) {
+ /* illegal comb. of pointer and int., op %s */
+ warning(123, mp->m_name);
+ } else {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ } else if (lt == PTR && rt == PTR) {
+ ptrcmpok(op, ln, rn);
+ }
+ break;
+ case QUEST:
+ if (!issclt(lt)) {
+ /* first operand must have scalar type, op ? : */
+ error(170);
+ return (0);
+ }
+ if (rn->tn_op != COLON)
+ lerror("typeok() 2");
+ break;
+ case COLON:
+
+ if (isatyp(lt) && isatyp(rt))
+ break;
+
+ if (lt == STRUCT && rt == STRUCT && ltp->t_str == rtp->t_str)
+ break;
+ if (lt == UNION && rt == UNION && ltp->t_str == rtp->t_str)
+ break;
+
+ /* combination of any pointer and 0, 0L or (void *)0 is ok */
+ if (lt == PTR && ((rt == PTR && rst == VOID) || isityp(rt))) {
+ if (rn->tn_op == CON && rn->tn_val->v_quad == 0)
+ break;
+ }
+ if (rt == PTR && ((lt == PTR && lst == VOID) || isityp(lt))) {
+ if (ln->tn_op == CON && ln->tn_val->v_quad == 0)
+ break;
+ }
+
+ if ((lt == PTR && isityp(rt)) || (isityp(lt) && rt == PTR)) {
+ /* illegal comb. of ptr. and int., op %s */
+ warning(123, mp->m_name);
+ break;
+ }
+
+ if (lt == VOID || rt == VOID) {
+ if (lt != VOID || rt != VOID)
+ /* incompatible types in conditional */
+ warning(126);
+ break;
+ }
+
+ if (lt == PTR && rt == PTR && ((lst == VOID && rst == FUNC) ||
+ (lst == FUNC && rst == VOID))) {
+ /* (void *)0 handled above */
+ if (sflag)
+ /* ANSI C forbids conv. of %s to %s, op %s */
+ warning(305, "function pointer", "'void *'",
+ mp->m_name);
+ break;
+ }
+
+ if (rt == PTR && lt == PTR) {
+ if (!eqtype(lstp, rstp, 1, 0, NULL))
+ illptrc(mp, ltp, rtp);
+ break;
+ }
+
+ /* incompatible types in conditional */
+ error(126);
+ return (0);
+
+ case ASSIGN:
+ case INIT:
+ case FARG:
+ case RETURN:
+ if (!asgntypok(op, arg, ln, rn))
+ return (0);
+ goto assign;
+ case MULASS:
+ case DIVASS:
+ case MODASS:
+ goto assign;
+ case ADDASS:
+ case SUBASS:
+ /* operands have scalar types (checked above) */
+ if ((lt == PTR && !isityp(rt)) || rt == PTR) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ goto assign;
+ case SHLASS:
+ goto assign;
+ case SHRASS:
+ if (pflag && !isutyp(lt) && !(tflag && isutyp(rt))) {
+ /* bitwise operation on s.v. possibly nonportabel */
+ warning(117);
+ }
+ goto assign;
+ case ANDASS:
+ case XORASS:
+ case ORASS:
+ goto assign;
+ assign:
+ if (!ln->tn_lvalue) {
+ if (ln->tn_op == CVT && ln->tn_cast &&
+ ln->tn_left->tn_op == LOAD) {
+ /* a cast does not yield an lvalue */
+ error(163);
+ }
+ /* %soperand of %s must be lvalue */
+ error(114, "left ", mp->m_name);
+ return (0);
+ } else if (ltp->t_const || ((lt == STRUCT || lt == UNION) &&
+ conmemb(ltp))) {
+ /* %soperand of %s must be modifiable lvalue */
+ if (!tflag)
+ warning(115, "left ", mp->m_name);
+ }
+ break;
+ case COMMA:
+ if (!modtab[ln->tn_op].m_sideeff)
+ nulleff(ln);
+ break;
+ /* LINTED (enumeration values not handled in switch) */
+ }
+
+ if (mp->m_badeop &&
+ (ltp->t_isenum || (mp->m_binary && rtp->t_isenum))) {
+ chkbeop(op, ln, rn);
+ } else if (mp->m_enumop && (ltp->t_isenum && rtp->t_isenum)) {
+ chkeop2(op, arg, ln, rn);
+ } else if (mp->m_enumop && (ltp->t_isenum || rtp->t_isenum)) {
+ chkeop1(op, arg, ln, rn);
+ }
+
+ return (1);
+}
+
+static void
+ptrcmpok(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ type_t *ltp, *rtp;
+ tspec_t lt, rt;
+ const char *lts, *rts;
+
+ lt = (ltp = ln->tn_type)->t_subt->t_tspec;
+ rt = (rtp = rn->tn_type)->t_subt->t_tspec;
+
+ if (lt == VOID || rt == VOID) {
+ if (sflag && (lt == FUNC || rt == FUNC)) {
+ /* (void *)0 already handled in typeok() */
+ *(lt == FUNC ? &lts : &rts) = "function pointer";
+ *(lt == VOID ? &lts : &rts) = "'void *'";
+ /* ANSI C forbids comparision of %s with %s */
+ warning(274, lts, rts);
+ }
+ return;
+ }
+
+ if (!eqtype(ltp->t_subt, rtp->t_subt, 1, 0, NULL)) {
+ illptrc(&modtab[op], ltp, rtp);
+ return;
+ }
+
+ if (lt == FUNC && rt == FUNC) {
+ if (sflag && op != EQ && op != NE)
+ /* ANSI C forbids ordered comp. of func ptr */
+ warning(125);
+ }
+}
+
+/*
+ * Checks type compatibility for ASSIGN, INIT, FARG and RETURN
+ * and prints warnings/errors if necessary.
+ * If the types are (almost) compatible, 1 is returned, otherwise 0.
+ */
+static int
+asgntypok(op, arg, ln, rn)
+ op_t op;
+ int arg;
+ tnode_t *ln, *rn;
+{
+ tspec_t lt, rt, lst, rst;
+ type_t *ltp, *rtp, *lstp, *rstp;
+ mod_t *mp;
+ const char *lts, *rts;
+
+ if ((lt = (ltp = ln->tn_type)->t_tspec) == PTR)
+ lst = (lstp = ltp->t_subt)->t_tspec;
+ if ((rt = (rtp = rn->tn_type)->t_tspec) == PTR)
+ rst = (rstp = rtp->t_subt)->t_tspec;
+ mp = &modtab[op];
+
+ if (isatyp(lt) && isatyp(rt))
+ return (1);
+
+ if ((lt == STRUCT || lt == UNION) && (rt == STRUCT || rt == UNION))
+ /* both are struct or union */
+ return (ltp->t_str == rtp->t_str);
+
+ /* 0, 0L and (void *)0 may be assigned to any pointer */
+ if (lt == PTR && ((rt == PTR && rst == VOID) || isityp(rt))) {
+ if (rn->tn_op == CON && rn->tn_val->v_quad == 0)
+ return (1);
+ }
+
+ if (lt == PTR && rt == PTR && (lst == VOID || rst == VOID)) {
+ /* two pointers, at least one pointer to void */
+ if (sflag && (lst == FUNC || rst == FUNC)) {
+ /* comb. of ptr to func and ptr to void */
+ *(lst == FUNC ? &lts : &rts) = "function pointer";
+ *(lst == VOID ? &lts : &rts) = "'void *'";
+ switch (op) {
+ case INIT:
+ case RETURN:
+ /* ANSI C forbids conversion of %s to %s */
+ warning(303, rts, lts);
+ break;
+ case FARG:
+ /* ANSI C forbids conv. of %s to %s, arg #%d */
+ warning(304, rts, lts, arg);
+ break;
+ default:
+ /* ANSI C forbids conv. of %s to %s, op %s */
+ warning(305, rts, lts, mp->m_name);
+ break;
+ }
+ }
+ }
+
+ if (lt == PTR && rt == PTR && (lst == VOID || rst == VOID ||
+ eqtype(lstp, rstp, 1, 0, NULL))) {
+ /* compatible pointer types (qualifiers ignored) */
+ if (!tflag &&
+ ((!lstp->t_const && rstp->t_const) ||
+ (!lstp->t_volatile && rstp->t_volatile))) {
+ /* left side has not all qualifiers of right */
+ switch (op) {
+ case INIT:
+ case RETURN:
+ /* incompatible pointer types */
+ warning(182);
+ break;
+ case FARG:
+ /* argument has incompat. ptr. type, arg #%d */
+ warning(153, arg);
+ break;
+ default:
+ /* operands have incompat. ptr. types, op %s */
+ warning(128, mp->m_name);
+ break;
+ }
+ }
+ return (1);
+ }
+
+ if ((lt == PTR && isityp(rt)) || (isityp(lt) && rt == PTR)) {
+ switch (op) {
+ case INIT:
+ case RETURN:
+ /* illegal combination of pointer and integer */
+ warning(183);
+ break;
+ case FARG:
+ /* illegal comb. of ptr. and int., arg #%d */
+ warning(154, arg);
+ break;
+ default:
+ /* illegal comb. of ptr. and int., op %s */
+ warning(123, mp->m_name);
+ break;
+ }
+ return (1);
+ }
+
+ if (lt == PTR && rt == PTR) {
+ switch (op) {
+ case INIT:
+ case RETURN:
+ illptrc(NULL, ltp, rtp);
+ break;
+ case FARG:
+ /* argument has incompatible pointer type, arg #%d */
+ warning(153, arg);
+ break;
+ default:
+ illptrc(mp, ltp, rtp);
+ break;
+ }
+ return (1);
+ }
+
+ switch (op) {
+ case INIT:
+ /* initialisation type mismatch */
+ error(185);
+ break;
+ case RETURN:
+ /* return value type mismatch */
+ error(211);
+ break;
+ case FARG:
+ /* argument is incompatible with prototype, arg #%d */
+ warning(155, arg);
+ break;
+ default:
+ incompat(op, lt, rt);
+ break;
+ }
+
+ return (0);
+}
+
+/*
+ * Prints a warning if an operator, which should be senseless for an
+ * enum type, is applied to an enum type.
+ */
+static void
+chkbeop(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ mod_t *mp;
+
+ if (!eflag)
+ return;
+
+ mp = &modtab[op];
+
+ if (!(ln->tn_type->t_isenum ||
+ (mp->m_binary && rn->tn_type->t_isenum))) {
+ return;
+ }
+
+ /*
+ * Enum as offset to a pointer is an exception (otherwise enums
+ * could not be used as array indizes).
+ */
+ if (op == PLUS &&
+ ((ln->tn_type->t_isenum && rn->tn_type->t_tspec == PTR) ||
+ (rn->tn_type->t_isenum && ln->tn_type->t_tspec == PTR))) {
+ return;
+ }
+
+ /* dubious operation on enum, op %s */
+ warning(241, mp->m_name);
+
+}
+
+/*
+ * Prints a warning if an operator is applied to two different enum types.
+ */
+static void
+chkeop2(op, arg, ln, rn)
+ op_t op;
+ int arg;
+ tnode_t *ln, *rn;
+{
+ mod_t *mp;
+
+ mp = &modtab[op];
+
+ if (ln->tn_type->t_enum != rn->tn_type->t_enum) {
+ switch (op) {
+ case INIT:
+ /* enum type mismatch in initialisation */
+ warning(210);
+ break;
+ case FARG:
+ /* enum type mismatch, arg #%d */
+ warning(156, arg);
+ break;
+ case RETURN:
+ /* return value type mismatch */
+ warning(211);
+ break;
+ default:
+ /* enum type mismatch, op %s */
+ warning(130, mp->m_name);
+ break;
+ }
+#if 0
+ } else if (mp->m_comp && op != EQ && op != NE) {
+ if (eflag)
+ /* dubious comparisions of enums */
+ warning(243, mp->m_name);
+#endif
+ }
+}
+
+/*
+ * Prints a warning if an operator has both enum end other integer
+ * types.
+ */
+static void
+chkeop1(op, arg, ln, rn)
+ op_t op;
+ int arg;
+ tnode_t *ln, *rn;
+{
+ if (!eflag)
+ return;
+
+ switch (op) {
+ case INIT:
+ /*
+ * Initializations with 0 should be allowed. Otherwise,
+ * we should complain about all uninitialized enums,
+ * consequently.
+ */
+ if (!rn->tn_type->t_isenum && rn->tn_op == CON &&
+ isityp(rn->tn_type->t_tspec) && rn->tn_val->v_quad == 0) {
+ return;
+ }
+ /* initialisation of '%s' with '%s' */
+ warning(277, tyname(ln->tn_type), tyname(rn->tn_type));
+ break;
+ case FARG:
+ /* combination of '%s' and '%s', arg #%d */
+ warning(278, tyname(ln->tn_type), tyname(rn->tn_type), arg);
+ break;
+ case RETURN:
+ /* combination of '%s' and '%s' in return */
+ warning(279, tyname(ln->tn_type), tyname(rn->tn_type));
+ break;
+ default:
+ /* combination of '%s' and %s, op %s */
+ warning(242, tyname(ln->tn_type), tyname(rn->tn_type),
+ modtab[op].m_name);
+ break;
+ }
+}
+
+/*
+ * Build and initialize a new node.
+ */
+static tnode_t *
+mktnode(op, type, ln, rn)
+ op_t op;
+ type_t *type;
+ tnode_t *ln, *rn;
+{
+ tnode_t *ntn;
+ tspec_t t;
+
+ ntn = getnode();
+
+ ntn->tn_op = op;
+ ntn->tn_type = type;
+ ntn->tn_left = ln;
+ ntn->tn_right = rn;
+
+ if (op == STAR || op == FSEL) {
+ if (ln->tn_type->t_tspec == PTR) {
+ t = ln->tn_type->t_subt->t_tspec;
+ if (t != FUNC && t != VOID)
+ ntn->tn_lvalue = 1;
+ } else {
+ lerror("mktnode() 2");
+ }
+ }
+
+ return (ntn);
+}
+
+/*
+ * Performs usual conversion of operands to (unsigned) int.
+ *
+ * If tflag is set or the operand is a function argument with no
+ * type information (no prototype or variable # of args), convert
+ * float to double.
+ */
+tnode_t *
+promote(op, farg, tn)
+ op_t op;
+ int farg;
+ tnode_t *tn;
+{
+ tspec_t t;
+ type_t *ntp;
+ int len;
+
+ t = tn->tn_type->t_tspec;
+
+ if (!isatyp(t))
+ return (tn);
+
+ if (!tflag) {
+ /*
+ * ANSI C requires that the result is always of type INT
+ * if INT can represent all possible values of the previous
+ * type.
+ */
+ if (tn->tn_type->t_isfield) {
+ len = tn->tn_type->t_flen;
+ if (size(INT) > len) {
+ t = INT;
+ } else {
+ if (size(INT) != len)
+ lerror("promote() 1");
+ if (isutyp(t)) {
+ t = UINT;
+ } else {
+ t = INT;
+ }
+ }
+ } else if (t == CHAR || t == UCHAR || t == SCHAR) {
+ t = (size(CHAR) < size(INT) || t != UCHAR) ?
+ INT : UINT;
+ } else if (t == SHORT || t == USHORT) {
+ t = (size(SHORT) < size(INT) || t == SHORT) ?
+ INT : UINT;
+ } else if (t == ENUM) {
+ t = INT;
+ } else if (farg && t == FLOAT) {
+ t = DOUBLE;
+ }
+ } else {
+ /*
+ * In traditional C, keep unsigned and promote FLOAT
+ * to DOUBLE.
+ */
+ if (t == UCHAR || t == USHORT) {
+ t = UINT;
+ } else if (t == CHAR || t == SCHAR || t == SHORT) {
+ t = INT;
+ } else if (t == FLOAT) {
+ t = DOUBLE;
+ } else if (t == ENUM) {
+ t = INT;
+ }
+ }
+
+ if (t != tn->tn_type->t_tspec) {
+ ntp = tduptyp(tn->tn_type);
+ ntp->t_tspec = t;
+ /*
+ * Keep t_isenum so we are later able to check compatibility
+ * of enum types.
+ */
+ tn = convert(op, 0, ntp, tn);
+ }
+
+ return (tn);
+}
+
+/*
+ * Insert conversions which are necessary to give both operands the same
+ * type. This is done in different ways for traditional C and ANIS C.
+ */
+static void
+balance(op, lnp, rnp)
+ op_t op;
+ tnode_t **lnp, **rnp;
+{
+ tspec_t lt, rt, t;
+ int i, u;
+ type_t *ntp;
+ static tspec_t tl[] = {
+ LDOUBLE, DOUBLE, FLOAT, UQUAD, QUAD, ULONG, LONG, UINT, INT,
+ };
+
+ lt = (*lnp)->tn_type->t_tspec;
+ rt = (*rnp)->tn_type->t_tspec;
+
+ if (!isatyp(lt) || !isatyp(rt))
+ return;
+
+ if (!tflag) {
+ if (lt == rt) {
+ t = lt;
+ } else if (lt == LDOUBLE || rt == LDOUBLE) {
+ t = LDOUBLE;
+ } else if (lt == DOUBLE || rt == DOUBLE) {
+ t = DOUBLE;
+ } else if (lt == FLOAT || rt == FLOAT) {
+ t = FLOAT;
+ } else {
+ /*
+ * If type A has more bits than type B it should
+ * be able to hold all possible values of type B.
+ */
+ if (size(lt) > size(rt)) {
+ t = lt;
+ } else if (size(lt) < size(rt)) {
+ t = rt;
+ } else {
+ for (i = 3; tl[i] != INT; i++) {
+ if (tl[i] == lt || tl[i] == rt)
+ break;
+ }
+ if ((isutyp(lt) || isutyp(rt)) &&
+ !isutyp(tl[i])) {
+ i--;
+ }
+ t = tl[i];
+ }
+ }
+ } else {
+ /* Keep unsigned in traditional C */
+ u = isutyp(lt) || isutyp(rt);
+ for (i = 0; tl[i] != INT; i++) {
+ if (lt == tl[i] || rt == tl[i])
+ break;
+ }
+ t = tl[i];
+ if (u && isityp(t) && !isutyp(t))
+ t = utyp(t);
+ }
+
+ if (t != lt) {
+ ntp = tduptyp((*lnp)->tn_type);
+ ntp->t_tspec = t;
+ *lnp = convert(op, 0, ntp, *lnp);
+ }
+ if (t != rt) {
+ ntp = tduptyp((*rnp)->tn_type);
+ ntp->t_tspec = t;
+ *rnp = convert(op, 0, ntp, *rnp);
+ }
+}
+
+/*
+ * Insert a conversion operator, which converts the type of the node
+ * to another given type.
+ * If op is FARG, arg is the number of the argument (used for warnings).
+ */
+tnode_t *
+convert(op, arg, tp, tn)
+ op_t op;
+ int arg;
+ type_t *tp;
+ tnode_t *tn;
+{
+ tnode_t *ntn;
+ tspec_t nt, ot, ost;
+
+ if (tn->tn_lvalue)
+ lerror("convert() 1");
+
+ nt = tp->t_tspec;
+ if ((ot = tn->tn_type->t_tspec) == PTR)
+ ost = tn->tn_type->t_subt->t_tspec;
+
+ if (!tflag && !sflag && op == FARG)
+ ptconv(arg, nt, ot, tp, tn);
+ if (isityp(nt) && isityp(ot)) {
+ iiconv(op, arg, nt, ot, tp, tn);
+ } else if (nt == PTR && ((ot == PTR && ost == VOID) || isityp(ot)) &&
+ tn->tn_op == CON && tn->tn_val->v_quad == 0) {
+ /* 0, 0L and (void *)0 may be assigned to any pointer. */
+ } else if (isityp(nt) && ot == PTR) {
+ piconv(op, nt, tp, tn);
+ } else if (nt == PTR && ot == PTR) {
+ ppconv(op, tn, tp);
+ }
+
+ ntn = getnode();
+ ntn->tn_op = CVT;
+ ntn->tn_type = tp;
+ ntn->tn_cast = op == CVT;
+ if (tn->tn_op != CON || nt == VOID) {
+ ntn->tn_left = tn;
+ } else {
+ ntn->tn_op = CON;
+ ntn->tn_val = tgetblk(sizeof (val_t));
+ cvtcon(op, arg, ntn->tn_type, ntn->tn_val, tn->tn_val);
+ }
+
+ return (ntn);
+}
+
+/*
+ * Print a warning if a prototype causes a type conversion that is
+ * different from what would happen to the same argument in the
+ * absence of a prototype.
+ *
+ * Errors/Warnings about illegal type combinations are already printed
+ * in asgntypok().
+ */
+static void
+ptconv(arg, nt, ot, tp, tn)
+ int arg;
+ tspec_t nt, ot;
+ type_t *tp;
+ tnode_t *tn;
+{
+ tnode_t *ptn;
+
+ if (!isatyp(nt) || !isatyp(ot))
+ return;
+
+ /*
+ * If the type of the formal parameter is char/short, a warning
+ * would be useless, because functions declared the old style
+ * can't expect char/short arguments.
+ */
+ if (nt == CHAR || nt == UCHAR || nt == SHORT || nt == USHORT)
+ return;
+
+ /* get default promotion */
+ ptn = promote(NOOP, 1, tn);
+ ot = ptn->tn_type->t_tspec;
+
+ /* return if types are the same with and without prototype */
+ if (nt == ot || (nt == ENUM && ot == INT))
+ return;
+
+ if (isftyp(nt) != isftyp(ot) || psize(nt) != psize(ot)) {
+ /* representation and/or width change */
+ if (styp(nt) != SHORT || !isityp(ot) || psize(ot) > psize(INT))
+ /* conversion to '%s' due to prototype, arg #%d */
+ warning(259, tyname(tp), arg);
+ } else if (hflag) {
+ /*
+ * they differ in sign or base type (char, short, int,
+ * long, long long, float, double, long double)
+ *
+ * if they differ only in sign and the argument is a constant
+ * and the msb of the argument is not set, print no warning
+ */
+ if (ptn->tn_op == CON && isityp(nt) && styp(nt) == styp(ot) &&
+ msb(ptn->tn_val->v_quad, ot, -1) == 0) {
+ /* ok */
+ } else {
+ /* conversion to '%s' due to prototype, arg #%d */
+ warning(259, tyname(tp), arg);
+ }
+ }
+}
+
+/*
+ * Print warnings for conversions of integer types which my cause
+ * problems.
+ */
+/* ARGSUSED */
+static void
+iiconv(op, arg, nt, ot, tp, tn)
+ op_t op;
+ int arg;
+ tspec_t nt, ot;
+ type_t *tp;
+ tnode_t *tn;
+{
+ if (tn->tn_op == CON)
+ return;
+
+ if (op == CVT)
+ return;
+
+#if 0
+ if (psize(nt) > psize(ot) && isutyp(nt) != isutyp(ot)) {
+ /* conversion to %s may sign-extend incorrectly (, arg #%d) */
+ if (aflag && pflag) {
+ if (op == FARG) {
+ warning(297, tyname(tp), arg);
+ } else {
+ warning(131, tyname(tp));
+ }
+ }
+ }
+#endif
+
+ if (psize(nt) < psize(ot) &&
+ (ot == LONG || ot == ULONG || ot == QUAD || ot == UQUAD ||
+ aflag > 1)) {
+ /* conversion from '%s' may lose accuracy */
+ if (aflag) {
+ if (op == FARG) {
+ warning(298, tyname(tn->tn_type), arg);
+ } else {
+ warning(132, tyname(tn->tn_type));
+ }
+ }
+ }
+}
+
+/*
+ * Print warnings for dubious conversions of pointer to integer.
+ */
+static void
+piconv(op, nt, tp, tn)
+ op_t op;
+ tspec_t nt;
+ type_t *tp;
+ tnode_t *tn;
+{
+ if (tn->tn_op == CON)
+ return;
+
+ if (op != CVT) {
+ /* We got already an error. */
+ return;
+ }
+
+ if (psize(nt) < psize(PTR)) {
+ if (pflag && size(nt) >= size(PTR)) {
+ /* conv. of pointer to %s may lose bits */
+ warning(134, tyname(tp));
+ } else {
+ /* conv. of pointer to %s loses bits */
+ warning(133, tyname(tp));
+ }
+ }
+}
+
+/*
+ * Print warnings for questionable pointer conversions.
+ */
+static void
+ppconv(op, tn, tp)
+ op_t op;
+ tnode_t *tn;
+ type_t *tp;
+{
+ tspec_t nt, ot;
+ const char *nts, *ots;
+
+ /*
+ * We got already an error (pointers of different types
+ * without a cast) or we will not get a warning.
+ */
+ if (op != CVT)
+ return;
+
+ nt = tp->t_subt->t_tspec;
+ ot = tn->tn_type->t_subt->t_tspec;
+
+ if (nt == VOID || ot == VOID) {
+ if (sflag && (nt == FUNC || ot == FUNC)) {
+ /* (void *)0 already handled in convert() */
+ *(nt == FUNC ? &nts : &ots) = "function pointer";
+ *(nt == VOID ? &nts : &ots) = "'void *'";
+ /* ANSI C forbids conversion of %s to %s */
+ warning(303, ots, nts);
+ }
+ return;
+ } else if (nt == FUNC && ot == FUNC) {
+ return;
+ } else if (nt == FUNC || ot == FUNC) {
+ /* questionable conversion of function pointer */
+ warning(229);
+ return;
+ }
+
+ if (getbound(tp->t_subt) > getbound(tn->tn_type->t_subt)) {
+ if (hflag)
+ /* possible pointer alignment problem */
+ warning(135);
+ }
+ if (((nt == STRUCT || nt == UNION) &&
+ tp->t_subt->t_str != tn->tn_type->t_subt->t_str) ||
+ psize(nt) != psize(ot)) {
+ if (cflag) {
+ /* pointer casts may be troublesome */
+ warning(247);
+ }
+ }
+}
+
+/*
+ * Converts a typed constant in a constant of another type.
+ *
+ * op operator which requires conversion
+ * arg if op is FARG, # of argument
+ * tp type in which to convert the constant
+ * nv new constant
+ * v old constant
+ */
+void
+cvtcon(op, arg, tp, nv, v)
+ op_t op;
+ int arg;
+ type_t *tp;
+ val_t *nv, *v;
+{
+ tspec_t ot, nt;
+ ldbl_t max, min;
+ int sz, rchk;
+ quad_t xmask, xmsk1;
+ int osz, nsz;
+
+ ot = v->v_tspec;
+ nt = nv->v_tspec = tp->t_tspec;
+ rchk = 0;
+
+ if (ot == FLOAT || ot == DOUBLE || ot == LDOUBLE) {
+ switch (nt) {
+ case CHAR:
+ max = CHAR_MAX; min = CHAR_MIN; break;
+ case UCHAR:
+ max = UCHAR_MAX; min = 0; break;
+ case SCHAR:
+ max = SCHAR_MAX; min = SCHAR_MIN; break;
+ case SHORT:
+ max = SHRT_MAX; min = SHRT_MIN; break;
+ case USHORT:
+ max = USHRT_MAX; min = 0; break;
+ case ENUM:
+ case INT:
+ max = INT_MAX; min = INT_MIN; break;
+ case UINT:
+ max = (u_int)UINT_MAX; min = 0; break;
+ case LONG:
+ max = LONG_MAX; min = LONG_MIN; break;
+ case ULONG:
+ max = (u_long)ULONG_MAX; min = 0; break;
+ case QUAD:
+ max = QUAD_MAX; min = QUAD_MIN; break;
+ case UQUAD:
+ max = (u_quad_t)UQUAD_MAX; min = 0; break;
+ case FLOAT:
+ max = FLT_MAX; min = -FLT_MAX; break;
+ case DOUBLE:
+ max = DBL_MAX; min = -DBL_MAX; break;
+ case PTR:
+ /* Got already an error because of float --> ptr */
+ case LDOUBLE:
+ max = LDBL_MAX; min = -LDBL_MAX; break;
+ default:
+ lerror("cvtcon() 1");
+ }
+ if (v->v_ldbl > max || v->v_ldbl < min) {
+ if (nt == LDOUBLE)
+ lerror("cvtcon() 2");
+ if (op == FARG) {
+ /* conv. of %s to %s is out of rng., arg #%d */
+ warning(295, tyname(gettyp(ot)), tyname(tp),
+ arg);
+ } else {
+ /* conversion of %s to %s is out of range */
+ warning(119, tyname(gettyp(ot)), tyname(tp));
+ }
+ v->v_ldbl = v->v_ldbl > 0 ? max : min;
+ }
+ if (nt == FLOAT) {
+ nv->v_ldbl = (float)v->v_ldbl;
+ } else if (nt == DOUBLE) {
+ nv->v_ldbl = (double)v->v_ldbl;
+ } else if (nt == LDOUBLE) {
+ nv->v_ldbl = v->v_ldbl;
+ } else {
+ nv->v_quad = (nt == PTR || isutyp(nt)) ?
+ (u_quad_t)v->v_ldbl : (quad_t)v->v_ldbl;
+ }
+ } else {
+ if (nt == FLOAT) {
+ nv->v_ldbl = (ot == PTR || isutyp(ot)) ?
+ (float)(u_quad_t)v->v_quad : (float)v->v_quad;
+ } else if (nt == DOUBLE) {
+ nv->v_ldbl = (ot == PTR || isutyp(ot)) ?
+ (double)(u_quad_t)v->v_quad : (double)v->v_quad;
+ } else if (nt == LDOUBLE) {
+ nv->v_ldbl = (ot == PTR || isutyp(ot)) ?
+ (ldbl_t)(u_quad_t)v->v_quad : (ldbl_t)v->v_quad;
+ } else {
+ rchk = 1; /* Check for lost precision. */
+ nv->v_quad = v->v_quad;
+ }
+ }
+
+ if (v->v_ansiu && isftyp(nt)) {
+ /* ANSI C treats constant as unsigned */
+ warning(157);
+ v->v_ansiu = 0;
+ } else if (v->v_ansiu && (isityp(nt) && !isutyp(nt) &&
+ psize(nt) > psize(ot))) {
+ /* ANSI C treats constant as unsigned */
+ warning(157);
+ v->v_ansiu = 0;
+ }
+
+ if (nt != FLOAT && nt != DOUBLE && nt != LDOUBLE) {
+ sz = tp->t_isfield ? tp->t_flen : size(nt);
+ nv->v_quad = xsign(nv->v_quad, nt, sz);
+ }
+
+ if (rchk && op != CVT) {
+ osz = size(ot);
+ nsz = tp->t_isfield ? tp->t_flen : size(nt);
+ xmask = qlmasks[nsz] ^ qlmasks[osz];
+ xmsk1 = qlmasks[nsz] ^ qlmasks[osz - 1];
+ /*
+ * For bitwise operations we are not interested in the
+ * value, but in the bits itself.
+ */
+ if (op == ORASS || op == OR || op == XOR) {
+ /*
+ * Print a warning if bits which were set are
+ * lost due to the conversion.
+ * This can happen with operator ORASS only.
+ */
+ if (nsz < osz && (v->v_quad & xmask) != 0) {
+ /* constant truncated by conv., op %s */
+ warning(306, modtab[op].m_name);
+ }
+ } else if (op == ANDASS || op == AND) {
+ /*
+ * Print a warning if additional bits are not all 1
+ * and the most significant bit of the old value is 1,
+ * or if at least one (but not all) removed bit was 0.
+ */
+ if (nsz > osz &&
+ (nv->v_quad & qbmasks[osz - 1]) != 0 &&
+ (nv->v_quad & xmask) != xmask) {
+ /*
+ * extra bits set to 0 in conversion
+ * of '%s' to '%s', op %s
+ */
+ warning(309, tyname(gettyp(ot)),
+ tyname(tp), modtab[op].m_name);
+ } else if (nsz < osz &&
+ (v->v_quad & xmask) != xmask &&
+ (v->v_quad & xmask) != 0) {
+ /* const. truncated by conv., op %s */
+ warning(306, modtab[op].m_name);
+ }
+ } else if ((nt != PTR && isutyp(nt)) &&
+ (ot != PTR && !isutyp(ot)) && v->v_quad < 0) {
+ if (op == ASSIGN) {
+ /* assignment of negative constant to ... */
+ warning(164);
+ } else if (op == INIT) {
+ /* initialisation of unsigned with neg. ... */
+ warning(221);
+ } else if (op == FARG) {
+ /* conversion of neg. const. to ..., arg #%d */
+ warning(296, arg);
+ } else if (modtab[op].m_comp) {
+ /* we get this warning already in chkcomp() */
+ } else {
+ /* conversion of negative constant to ... */
+ warning(222);
+ }
+ } else if (nv->v_quad != v->v_quad && nsz <= osz &&
+ (v->v_quad & xmask) != 0 &&
+ (isutyp(ot) || (v->v_quad & xmsk1) != xmsk1)) {
+ /*
+ * Loss of significant bit(s). All truncated bits
+ * of unsigned types or all truncated bits plus the
+ * msb of the target for signed types are considered
+ * to be significant bits. Loss of significant bits
+ * means that at least on of the bits was set in an
+ * unsigned type or that at least one, but not all of
+ * the bits was set in an signed type.
+ * Loss of significant bits means that it is not
+ * possible, also not with necessary casts, to convert
+ * back to the original type. A example for a
+ * necessary cast is:
+ * char c; int i; c = 128;
+ * i = c; ** yields -128 **
+ * i = (unsigned char)c; ** yields 128 **
+ */
+ if (op == ASSIGN && tp->t_isfield) {
+ /* precision lost in bit-field assignment */
+ warning(166);
+ } else if (op == ASSIGN) {
+ /* constant truncated by assignment */
+ warning(165);
+ } else if (op == INIT && tp->t_isfield) {
+ /* bit-field initializer does not fit */
+ warning(180);
+ } else if (op == INIT) {
+ /* initializer does not fit */
+ warning(178);
+ } else if (op == CASE) {
+ /* case label affected by conversion */
+ warning(196);
+ } else if (op == FARG) {
+ /* conv. of %s to %s is out of rng., arg #%d */
+ warning(295, tyname(gettyp(ot)), tyname(tp),
+ arg);
+ } else {
+ /* conversion of %s to %s is out of range */
+ warning(119, tyname(gettyp(ot)), tyname(tp));
+ }
+ } else if (nv->v_quad != v->v_quad) {
+ if (op == ASSIGN && tp->t_isfield) {
+ /* precision lost in bit-field assignment */
+ warning(166);
+ } else if (op == INIT && tp->t_isfield) {
+ /* bit-field initializer out of range */
+ warning(11);
+ } else if (op == CASE) {
+ /* case label affected by conversion */
+ warning(196);
+ } else if (op == FARG) {
+ /* conv. of %s to %s is out of rng., arg #%d */
+ warning(295, tyname(gettyp(ot)), tyname(tp),
+ arg);
+ } else {
+ /* conversion of %s to %s is out of range */
+ warning(119, tyname(gettyp(ot)), tyname(tp));
+ }
+ }
+ }
+}
+
+/*
+ * Called if incompatible types were detected.
+ * Prints a appropriate warning.
+ */
+static void
+incompat(op, lt, rt)
+ op_t op;
+ tspec_t lt, rt;
+{
+ mod_t *mp;
+
+ mp = &modtab[op];
+
+ if (lt == VOID || (mp->m_binary && rt == VOID)) {
+ /* void type illegal in expression */
+ error(109);
+ } else if (op == ASSIGN) {
+ if ((lt == STRUCT || lt == UNION) &&
+ (rt == STRUCT || rt == UNION)) {
+ /* assignment of different structures */
+ error(240);
+ } else {
+ /* assignment type mismatch */
+ error(171);
+ }
+ } else if (mp->m_binary) {
+ /* operands of %s have incompatible types */
+ error(107, mp->m_name);
+ } else {
+ /* operand of %s has incompatible type */
+ error(108, mp->m_name);
+ }
+}
+
+/*
+ * Called if incompatible pointer types are detected.
+ * Print an appropriate warning.
+ */
+static void
+illptrc(mp, ltp, rtp)
+ mod_t *mp;
+ type_t *ltp, *rtp;
+{
+ tspec_t lt, rt;
+
+ if (ltp->t_tspec != PTR || rtp->t_tspec != PTR)
+ lerror("illptrc() 1");
+
+ lt = ltp->t_subt->t_tspec;
+ rt = rtp->t_subt->t_tspec;
+
+ if ((lt == STRUCT || lt == UNION) && (rt == STRUCT || rt == UNION)) {
+ if (mp == NULL) {
+ /* illegal structure pointer combination */
+ warning(244);
+ } else {
+ /* illegal structure pointer combination, op %s */
+ warning(245, mp->m_name);
+ }
+ } else {
+ if (mp == NULL) {
+ /* illegal pointer combination */
+ warning(184);
+ } else {
+ /* illegal pointer combination, op %s */
+ warning(124, mp->m_name);
+ }
+ }
+}
+
+/*
+ * Make sure type (*tpp)->t_subt has at least the qualifiers
+ * of tp1->t_subt and tp2->t_subt.
+ */
+static void
+mrgqual(tpp, tp1, tp2)
+ type_t **tpp, *tp1, *tp2;
+{
+ if ((*tpp)->t_tspec != PTR ||
+ tp1->t_tspec != PTR || tp2->t_tspec != PTR) {
+ lerror("mrgqual()");
+ }
+
+ if ((*tpp)->t_subt->t_const ==
+ (tp1->t_subt->t_const | tp2->t_subt->t_const) &&
+ (*tpp)->t_subt->t_volatile ==
+ (tp1->t_subt->t_volatile | tp2->t_subt->t_volatile)) {
+ return;
+ }
+
+ *tpp = tduptyp(*tpp);
+ (*tpp)->t_subt = tduptyp((*tpp)->t_subt);
+ (*tpp)->t_subt->t_const =
+ tp1->t_subt->t_const | tp2->t_subt->t_const;
+ (*tpp)->t_subt->t_volatile =
+ tp1->t_subt->t_volatile | tp2->t_subt->t_volatile;
+}
+
+/*
+ * Returns 1 if the given structure or union has a constant member
+ * (maybe recursively).
+ */
+static int
+conmemb(tp)
+ type_t *tp;
+{
+ sym_t *m;
+ tspec_t t;
+
+ if ((t = tp->t_tspec) != STRUCT && t != UNION)
+ lerror("conmemb()");
+ for (m = tp->t_str->memb; m != NULL; m = m->s_nxt) {
+ tp = m->s_type;
+ if (tp->t_const)
+ return (1);
+ if ((t = tp->t_tspec) == STRUCT || t == UNION) {
+ if (conmemb(m->s_type))
+ return (1);
+ }
+ }
+ return (0);
+}
+
+const char *
+tyname(tp)
+ type_t *tp;
+{
+ tspec_t t;
+ const char *s;
+
+ if ((t = tp->t_tspec) == INT && tp->t_isenum)
+ t = ENUM;
+
+ switch (t) {
+ case CHAR: s = "char"; break;
+ case UCHAR: s = "unsigned char"; break;
+ case SCHAR: s = "signed char"; break;
+ case SHORT: s = "short"; break;
+ case USHORT: s = "unsigned short"; break;
+ case INT: s = "int"; break;
+ case UINT: s = "unsigned int"; break;
+ case LONG: s = "long"; break;
+ case ULONG: s = "unsigned long"; break;
+ case QUAD: s = "long long"; break;
+ case UQUAD: s = "unsigned long long"; break;
+ case FLOAT: s = "float"; break;
+ case DOUBLE: s = "double"; break;
+ case LDOUBLE: s = "long double"; break;
+ case PTR: s = "pointer"; break;
+ case ENUM: s = "enum"; break;
+ case STRUCT: s = "struct"; break;
+ case UNION: s = "union"; break;
+ case FUNC: s = "function"; break;
+ case ARRAY: s = "array"; break;
+ default:
+ lerror("tyname()");
+ }
+ return (s);
+}
+
+/*
+ * Create a new node for one of the operators POINT and ARROW.
+ */
+static tnode_t *
+bldstr(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tnode_t *ntn, *ctn;
+ int nolval;
+
+ if (rn->tn_op != NAME)
+ lerror("bldstr() 1");
+ if (rn->tn_sym->s_value.v_tspec != INT)
+ lerror("bldstr() 2");
+ if (rn->tn_sym->s_scl != MOS && rn->tn_sym->s_scl != MOU)
+ lerror("bldstr() 3");
+
+ /*
+ * Remember if the left operand is an lvalue (structure members
+ * are lvalues if and only if the structure itself is an lvalue).
+ */
+ nolval = op == POINT && !ln->tn_lvalue;
+
+ if (op == POINT) {
+ ln = bldamper(ln, 1);
+ } else if (ln->tn_type->t_tspec != PTR) {
+ if (!tflag || !isityp(ln->tn_type->t_tspec))
+ lerror("bldstr() 4");
+ ln = convert(NOOP, 0, tincref(gettyp(VOID), PTR), ln);
+ }
+
+#if PTRDIFF_IS_LONG
+ ctn = getinode(LONG, rn->tn_sym->s_value.v_quad / CHAR_BIT);
+#else
+ ctn = getinode(INT, rn->tn_sym->s_value.v_quad / CHAR_BIT);
+#endif
+
+ ntn = mktnode(PLUS, tincref(rn->tn_type, PTR), ln, ctn);
+ if (ln->tn_op == CON)
+ ntn = fold(ntn);
+
+ if (rn->tn_type->t_isfield) {
+ ntn = mktnode(FSEL, ntn->tn_type->t_subt, ntn, NULL);
+ } else {
+ ntn = mktnode(STAR, ntn->tn_type->t_subt, ntn, NULL);
+ }
+
+ if (nolval)
+ ntn->tn_lvalue = 0;
+
+ return (ntn);
+}
+
+/*
+ * Create a node for INCAFT, INCBEF, DECAFT and DECBEF.
+ */
+static tnode_t *
+bldincdec(op, ln)
+ op_t op;
+ tnode_t *ln;
+{
+ tnode_t *cn, *ntn;
+
+ if (ln == NULL)
+ lerror("bldincdec() 1");
+
+ if (ln->tn_type->t_tspec == PTR) {
+ cn = plength(ln->tn_type);
+ } else {
+ cn = getinode(INT, (quad_t)1);
+ }
+ ntn = mktnode(op, ln->tn_type, ln, cn);
+
+ return (ntn);
+}
+
+/*
+ * Create a tree node for the & operator
+ */
+static tnode_t *
+bldamper(tn, noign)
+ tnode_t *tn;
+ int noign;
+{
+ tnode_t *ntn;
+ tspec_t t;
+
+ if (!noign && ((t = tn->tn_type->t_tspec) == ARRAY || t == FUNC)) {
+ /* & before array or function: ignored */
+ if (tflag)
+ warning(127);
+ return (tn);
+ }
+
+ /* eliminate &* */
+ if (tn->tn_op == STAR &&
+ tn->tn_left->tn_type->t_tspec == PTR &&
+ tn->tn_left->tn_type->t_subt == tn->tn_type) {
+ return (tn->tn_left);
+ }
+
+ ntn = mktnode(AMPER, tincref(tn->tn_type, PTR), tn, NULL);
+
+ return (ntn);
+}
+
+/*
+ * Create a node for operators PLUS and MINUS.
+ */
+static tnode_t *
+bldplmi(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tnode_t *ntn, *ctn;
+ type_t *tp;
+
+ /* If pointer and integer, then pointer to the lhs. */
+ if (rn->tn_type->t_tspec == PTR && isityp(ln->tn_type->t_tspec)) {
+ ntn = ln;
+ ln = rn;
+ rn = ntn;
+ }
+
+ if (ln->tn_type->t_tspec == PTR && rn->tn_type->t_tspec != PTR) {
+
+ if (!isityp(rn->tn_type->t_tspec))
+ lerror("bldplmi() 1");
+
+ ctn = plength(ln->tn_type);
+ if (rn->tn_type->t_tspec != ctn->tn_type->t_tspec)
+ rn = convert(NOOP, 0, ctn->tn_type, rn);
+ rn = mktnode(MULT, rn->tn_type, rn, ctn);
+ if (rn->tn_left->tn_op == CON)
+ rn = fold(rn);
+ ntn = mktnode(op, ln->tn_type, ln, rn);
+
+ } else if (rn->tn_type->t_tspec == PTR) {
+
+ if (ln->tn_type->t_tspec != PTR || op != MINUS)
+ lerror("bldplmi() 2");
+#if PTRDIFF_IS_LONG
+ tp = gettyp(LONG);
+#else
+ tp = gettyp(INT);
+#endif
+ ntn = mktnode(op, tp, ln, rn);
+ if (ln->tn_op == CON && rn->tn_op == CON)
+ ntn = fold(ntn);
+ ctn = plength(ln->tn_type);
+ balance(NOOP, &ntn, &ctn);
+ ntn = mktnode(DIV, tp, ntn, ctn);
+
+ } else {
+
+ ntn = mktnode(op, ln->tn_type, ln, rn);
+
+ }
+ return (ntn);
+}
+
+/*
+ * Create a node for operators SHL and SHR.
+ */
+static tnode_t *
+bldshft(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tspec_t t;
+ tnode_t *ntn;
+
+ if ((t = rn->tn_type->t_tspec) != INT && t != UINT)
+ rn = convert(CVT, 0, gettyp(INT), rn);
+ ntn = mktnode(op, ln->tn_type, ln, rn);
+ return (ntn);
+}
+
+/*
+ * Create a node for COLON.
+ */
+static tnode_t *
+bldcol(ln, rn)
+ tnode_t *ln, *rn;
+{
+ tspec_t lt, rt, pdt;
+ type_t *rtp;
+ tnode_t *ntn;
+
+ lt = ln->tn_type->t_tspec;
+ rt = rn->tn_type->t_tspec;
+#if PTRDIFF_IS_LONG
+ pdt = LONG;
+#else
+ pdt = INT;
+#endif
+
+ /*
+ * Arithmetic types are balanced, all other type combinations
+ * still need to be handled.
+ */
+ if (isatyp(lt) && isatyp(rt)) {
+ rtp = ln->tn_type;
+ } else if (lt == VOID || rt == VOID) {
+ rtp = gettyp(VOID);
+ } else if (lt == STRUCT || lt == UNION) {
+ /* Both types must be identical. */
+ if (rt != STRUCT && rt != UNION)
+ lerror("bldcol() 1");
+ if (ln->tn_type->t_str != rn->tn_type->t_str)
+ lerror("bldcol() 2");
+ if (incompl(ln->tn_type)) {
+ /* unknown operand size, op %s */
+ error(138, modtab[COLON].m_name);
+ return (NULL);
+ }
+ rtp = ln->tn_type;
+ } else if (lt == PTR && isityp(rt)) {
+ if (rt != pdt) {
+ rn = convert(NOOP, 0, gettyp(pdt), rn);
+ rt = pdt;
+ }
+ rtp = ln->tn_type;
+ } else if (rt == PTR && isityp(lt)) {
+ if (lt != pdt) {
+ ln = convert(NOOP, 0, gettyp(pdt), ln);
+ lt = pdt;
+ }
+ rtp = rn->tn_type;
+ } else if (lt == PTR && ln->tn_type->t_subt->t_tspec == VOID) {
+ if (rt != PTR)
+ lerror("bldcol() 4");
+ rtp = ln->tn_type;
+ mrgqual(&rtp, ln->tn_type, rn->tn_type);
+ } else if (rt == PTR && rn->tn_type->t_subt->t_tspec == VOID) {
+ if (lt != PTR)
+ lerror("bldcol() 5");
+ rtp = rn->tn_type;
+ mrgqual(&rtp, ln->tn_type, rn->tn_type);
+ } else {
+ if (lt != PTR || rt != PTR)
+ lerror("bldcol() 6");
+ /*
+ * XXX For now we simply take the left type. This is
+ * probably wrong, if one type contains a functionprototype
+ * and the other one, at the same place, only an old style
+ * declaration.
+ */
+ rtp = ln->tn_type;
+ mrgqual(&rtp, ln->tn_type, rn->tn_type);
+ }
+
+ ntn = mktnode(COLON, rtp, ln, rn);
+
+ return (ntn);
+}
+
+/*
+ * Create a node for an assignment operator (both = and op= ).
+ */
+static tnode_t *
+bldasgn(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tspec_t lt, rt;
+ tnode_t *ntn, *ctn;
+
+ if (ln == NULL || rn == NULL)
+ lerror("bldasgn() 1");
+
+ lt = ln->tn_type->t_tspec;
+ rt = rn->tn_type->t_tspec;
+
+ if ((op == ADDASS || op == SUBASS) && lt == PTR) {
+ if (!isityp(rt))
+ lerror("bldasgn() 2");
+ ctn = plength(ln->tn_type);
+ if (rn->tn_type->t_tspec != ctn->tn_type->t_tspec)
+ rn = convert(NOOP, 0, ctn->tn_type, rn);
+ rn = mktnode(MULT, rn->tn_type, rn, ctn);
+ if (rn->tn_left->tn_op == CON)
+ rn = fold(rn);
+ }
+
+ if ((op == ASSIGN || op == RETURN) && (lt == STRUCT || rt == STRUCT)) {
+ if (rt != lt || ln->tn_type->t_str != rn->tn_type->t_str)
+ lerror("bldasgn() 3");
+ if (incompl(ln->tn_type)) {
+ if (op == RETURN) {
+ /* cannot return incomplete type */
+ error(212);
+ } else {
+ /* unknown operand size, op %s */
+ error(138, modtab[op].m_name);
+ }
+ return (NULL);
+ }
+ }
+
+ if (op == SHLASS || op == SHRASS) {
+ if (rt != INT) {
+ rn = convert(NOOP, 0, gettyp(INT), rn);
+ rt = INT;
+ }
+ } else {
+ if (op == ASSIGN || lt != PTR) {
+ if (lt != rt ||
+ (ln->tn_type->t_isfield && rn->tn_op == CON)) {
+ rn = convert(op, 0, ln->tn_type, rn);
+ rt = lt;
+ }
+ }
+ }
+
+ ntn = mktnode(op, ln->tn_type, ln, rn);
+
+ return (ntn);
+}
+
+/*
+ * Get length of type tp->t_subt.
+ */
+static tnode_t *
+plength(tp)
+ type_t *tp;
+{
+ int elem, elsz;
+ tspec_t st;
+
+ if (tp->t_tspec != PTR)
+ lerror("plength() 1");
+ tp = tp->t_subt;
+
+ elem = 1;
+ elsz = 0;
+
+ while (tp->t_tspec == ARRAY) {
+ elem *= tp->t_dim;
+ tp = tp->t_subt;
+ }
+
+ switch (tp->t_tspec) {
+ case FUNC:
+ /* pointer to function is not allowed here */
+ error(110);
+ break;
+ case VOID:
+ /* cannot do pointer arithmetic on operand of ... */
+ (void)gnuism(136);
+ break;
+ case STRUCT:
+ case UNION:
+ if ((elsz = tp->t_str->size) == 0)
+ /* cannot do pointer arithmetic on operand of ... */
+ error(136);
+ break;
+ case ENUM:
+ if (incompl(tp)) {
+ /* cannot do pointer arithmetic on operand of ... */
+ warning(136);
+ }
+ /* FALLTHROUGH */
+ default:
+ if ((elsz = size(tp->t_tspec)) == 0) {
+ /* cannot do pointer arithmetic on operand of ... */
+ error(136);
+ } else if (elsz == -1) {
+ lerror("plength() 2");
+ }
+ break;
+ }
+
+ if (elem == 0 && elsz != 0) {
+ /* cannot do pointer arithmetic on operand of ... */
+ error(136);
+ }
+
+ if (elsz == 0)
+ elsz = CHAR_BIT;
+
+#if PTRDIFF_IS_LONG
+ st = LONG;
+#else
+ st = INT;
+#endif
+
+ return (getinode(st, (quad_t)(elem * elsz / CHAR_BIT)));
+}
+
+#ifdef XXX_BROKEN_GCC
+static int
+quad_t_eq(x, y)
+ quad_t x, y;
+{
+ return (x == y);
+}
+
+static int
+u_quad_t_eq(x, y)
+ u_quad_t x, y;
+{
+ return (x == y);
+}
+#endif
+
+/*
+ * Do only as much as necessary to compute constant expressions.
+ * Called only if the operator allows folding and (both) operands
+ * are constants.
+ */
+static tnode_t *
+fold(tn)
+ tnode_t *tn;
+{
+ val_t *v;
+ tspec_t t;
+ int utyp, ovfl;
+ quad_t sl, sr, q, mask;
+ u_quad_t ul, ur;
+ tnode_t *cn;
+
+ v = xcalloc(1, sizeof (val_t));
+ v->v_tspec = t = tn->tn_type->t_tspec;
+
+ utyp = t == PTR || isutyp(t);
+ ul = sl = tn->tn_left->tn_val->v_quad;
+ if (modtab[tn->tn_op].m_binary)
+ ur = sr = tn->tn_right->tn_val->v_quad;
+
+ ovfl = 0;
+
+ switch (tn->tn_op) {
+ case UPLUS:
+ q = sl;
+ break;
+ case UMINUS:
+ q = -sl;
+ if (msb(q, t, -1) == msb(sl, t, -1))
+ ovfl = 1;
+ break;
+ case COMPL:
+ q = ~sl;
+ break;
+ case MULT:
+ q = utyp ? ul * ur : sl * sr;
+ if (msb(q, t, -1) != (msb(sl, t, -1) ^ msb(sr, t, -1)))
+ ovfl = 1;
+ break;
+ case DIV:
+ if (sr == 0) {
+ /* division by 0 */
+ error(139);
+ q = utyp ? UQUAD_MAX : QUAD_MAX;
+ } else {
+ q = utyp ? ul / ur : sl / sr;
+ }
+ break;
+ case MOD:
+ if (sr == 0) {
+ /* modulus by 0 */
+ error(140);
+ q = 0;
+ } else {
+ q = utyp ? ul % ur : sl % sr;
+ }
+ break;
+ case PLUS:
+ q = utyp ? ul + ur : sl + sr;
+ if (msb(sl, t, -1) != 0 && msb(sr, t, -1) != 0) {
+ if (msb(q, t, -1) == 0)
+ ovfl = 1;
+ } else if (msb(sl, t, -1) == 0 && msb(sr, t, -1) == 0) {
+ if (msb(q, t, -1) != 0)
+ ovfl = 1;
+ }
+ break;
+ case MINUS:
+ q = utyp ? ul - ur : sl - sr;
+ if (msb(sl, t, -1) != 0 && msb(sr, t, -1) == 0) {
+ if (msb(q, t, -1) == 0)
+ ovfl = 1;
+ } else if (msb(sl, t, -1) == 0 && msb(sr, t, -1) != 0) {
+ if (msb(q, t, -1) != 0)
+ ovfl = 1;
+ }
+ break;
+ case SHL:
+ q = utyp ? ul << sr : sl << sr;
+ break;
+ case SHR:
+ /*
+ * The sign must be explizitly extended because
+ * shifts of signed values are implementation dependent.
+ */
+ q = ul >> sr;
+ q = xsign(q, t, size(t) - (int)sr);
+ break;
+ case LT:
+ q = utyp ? ul < ur : sl < sr;
+ break;
+ case LE:
+ q = utyp ? ul <= ur : sl <= sr;
+ break;
+ case GE:
+ q = utyp ? ul >= ur : sl >= sr;
+ break;
+ case GT:
+ q = utyp ? ul > ur : sl > sr;
+ break;
+ case EQ:
+#ifdef XXX_BROKEN_GCC
+ q = utyp ? u_quad_t_eq(ul, ur) : quad_t_eq(sl, sr);
+#else
+ q = utyp ? ul == ur : sl == sr;
+#endif
+ break;
+ case NE:
+ q = utyp ? ul != ur : sl != sr;
+ break;
+ case AND:
+ q = utyp ? ul & ur : sl & sr;
+ break;
+ case XOR:
+ q = utyp ? ul ^ ur : sl ^ sr;
+ break;
+ case OR:
+ q = utyp ? ul | ur : sl | sr;
+ break;
+ default:
+ lerror("fold() 5");
+ }
+
+ mask = qlmasks[size(t)];
+
+ /* XXX does not work for quads. */
+ if (ovfl || ((q | mask) != ~(u_quad_t)0 && (q & ~mask) != 0)) {
+ if (hflag)
+ /* integer overflow detected, op %s */
+ warning(141, modtab[tn->tn_op].m_name);
+ }
+
+ v->v_quad = xsign(q, t, -1);
+
+ cn = getcnode(tn->tn_type, v);
+
+ return (cn);
+}
+
+#ifdef XXX_BROKEN_GCC
+int
+ldbl_t_neq(x, y)
+ ldbl_t x, y;
+{
+ return (x != y);
+}
+#endif
+
+/*
+ * Same for operators whose operands are compared with 0 (test context).
+ */
+static tnode_t *
+foldtst(tn)
+ tnode_t *tn;
+{
+ int l, r;
+ val_t *v;
+
+ v = xcalloc(1, sizeof (val_t));
+ v->v_tspec = tn->tn_type->t_tspec;
+ if (tn->tn_type->t_tspec != INT)
+ lerror("foldtst() 1");
+
+ if (isftyp(tn->tn_left->tn_type->t_tspec)) {
+#ifdef XXX_BROKEN_GCC
+ l = ldbl_t_neq(tn->tn_left->tn_val->v_ldbl, 0.0);
+#else
+ l = tn->tn_left->tn_val->v_ldbl != 0.0;
+#endif
+ } else {
+ l = tn->tn_left->tn_val->v_quad != 0;
+ }
+
+ if (modtab[tn->tn_op].m_binary) {
+ if (isftyp(tn->tn_right->tn_type->t_tspec)) {
+#ifdef XXX_BROKEN_GCC
+ r = ldbl_t_neq(tn->tn_right->tn_val->v_ldbl, 0.0);
+#else
+ r = tn->tn_right->tn_val->v_ldbl != 0.0;
+#endif
+ } else {
+ r = tn->tn_right->tn_val->v_quad != 0;
+ }
+ }
+
+ switch (tn->tn_op) {
+ case NOT:
+ if (hflag)
+ /* constant argument to NOT */
+ warning(239);
+ v->v_quad = !l;
+ break;
+ case LOGAND:
+ v->v_quad = l && r;
+ break;
+ case LOGOR:
+ v->v_quad = l || r;
+ break;
+ default:
+ lerror("foldtst() 1");
+ }
+
+ return (getcnode(tn->tn_type, v));
+}
+
+/*
+ * Same for operands with floating point type.
+ */
+static tnode_t *
+foldflt(tn)
+ tnode_t *tn;
+{
+ val_t *v;
+ tspec_t t;
+ ldbl_t l, r;
+
+ v = xcalloc(1, sizeof (val_t));
+ v->v_tspec = t = tn->tn_type->t_tspec;
+
+ if (!isftyp(t))
+ lerror("foldflt() 1");
+
+ if (t != tn->tn_left->tn_type->t_tspec)
+ lerror("foldflt() 2");
+ if (modtab[tn->tn_op].m_binary && t != tn->tn_right->tn_type->t_tspec)
+ lerror("foldflt() 3");
+
+ l = tn->tn_left->tn_val->v_ldbl;
+ if (modtab[tn->tn_op].m_binary)
+ r = tn->tn_right->tn_val->v_ldbl;
+
+ switch (tn->tn_op) {
+ case UPLUS:
+ v->v_ldbl = l;
+ break;
+ case UMINUS:
+ v->v_ldbl = -l;
+ break;
+ case MULT:
+ v->v_ldbl = l * r;
+ break;
+ case DIV:
+ if (r == 0.0) {
+ /* division by 0 */
+ error(139);
+ if (t == FLOAT) {
+ v->v_ldbl = l < 0 ? -FLT_MAX : FLT_MAX;
+ } else if (t == DOUBLE) {
+ v->v_ldbl = l < 0 ? -DBL_MAX : DBL_MAX;
+ } else {
+ v->v_ldbl = l < 0 ? -LDBL_MAX : LDBL_MAX;
+ }
+ } else {
+ v->v_ldbl = l / r;
+ }
+ break;
+ case PLUS:
+ v->v_ldbl = l + r;
+ break;
+ case MINUS:
+ v->v_ldbl = l - r;
+ break;
+ case LT:
+ v->v_quad = l < r;
+ break;
+ case LE:
+ v->v_quad = l <= r;
+ break;
+ case GE:
+ v->v_quad = l >= r;
+ break;
+ case GT:
+ v->v_quad = l > r;
+ break;
+ case EQ:
+ v->v_quad = l == r;
+ break;
+ case NE:
+ v->v_quad = l != r;
+ break;
+ default:
+ lerror("foldflt() 4");
+ }
+
+ if (isnan((double)v->v_ldbl))
+ lerror("foldflt() 5");
+ if (isinf((double)v->v_ldbl) ||
+ (t == FLOAT &&
+ (v->v_ldbl > FLT_MAX || v->v_ldbl < -FLT_MAX)) ||
+ (t == DOUBLE &&
+ (v->v_ldbl > DBL_MAX || v->v_ldbl < -DBL_MAX))) {
+ /* floating point overflow detected, op %s */
+ warning(142, modtab[tn->tn_op].m_name);
+ if (t == FLOAT) {
+ v->v_ldbl = v->v_ldbl < 0 ? -FLT_MAX : FLT_MAX;
+ } else if (t == DOUBLE) {
+ v->v_ldbl = v->v_ldbl < 0 ? -DBL_MAX : DBL_MAX;
+ } else {
+ v->v_ldbl = v->v_ldbl < 0 ? -LDBL_MAX: LDBL_MAX;
+ }
+ }
+
+ return (getcnode(tn->tn_type, v));
+}
+
+/*
+ * Create a constant node for sizeof.
+ */
+tnode_t *
+bldszof(tp)
+ type_t *tp;
+{
+ int elem, elsz;
+ tspec_t st;
+
+ elem = 1;
+ while (tp->t_tspec == ARRAY) {
+ elem *= tp->t_dim;
+ tp = tp->t_subt;
+ }
+ if (elem == 0) {
+ /* cannot take size of incomplete type */
+ error(143);
+ elem = 1;
+ }
+ switch (tp->t_tspec) {
+ case FUNC:
+ /* cannot take size of function */
+ error(144);
+ elsz = 1;
+ break;
+ case STRUCT:
+ case UNION:
+ if (incompl(tp)) {
+ /* cannot take size of incomplete type */
+ error(143);
+ elsz = 1;
+ } else {
+ elsz = tp->t_str->size;
+ }
+ break;
+ case ENUM:
+ if (incompl(tp)) {
+ /* cannot take size of incomplete type */
+ warning(143);
+ }
+ /* FALLTHROUGH */
+ default:
+ if (tp->t_isfield) {
+ /* cannot take size of bit-field */
+ error(145);
+ }
+ if (tp->t_tspec == VOID) {
+ /* cannot take size of void */
+ error(146);
+ elsz = 1;
+ } else {
+ elsz = size(tp->t_tspec);
+ if (elsz <= 0)
+ lerror("bldszof() 1");
+ }
+ break;
+ }
+
+#if SIZEOF_IS_ULONG
+ st = ULONG;
+#else
+ st = UINT;
+#endif
+
+ return (getinode(st, (quad_t)(elem * elsz / CHAR_BIT)));
+}
+
+/*
+ * Type casts.
+ */
+tnode_t *
+cast(tn, tp)
+ tnode_t *tn;
+ type_t *tp;
+{
+ tspec_t nt, ot;
+
+ if (tn == NULL)
+ return (NULL);
+
+ tn = cconv(tn);
+
+ nt = tp->t_tspec;
+ ot = tn->tn_type->t_tspec;
+
+ if (nt == VOID) {
+ /*
+ * XXX ANSI C requires scalar types or void (Plauger&Brodie).
+ * But this seams really questionable.
+ */
+ } else if (nt == STRUCT || nt == UNION || nt == ARRAY || nt == FUNC) {
+ /* invalid cast expression */
+ error(147);
+ return (NULL);
+ } else if (ot == STRUCT || ot == UNION) {
+ /* invalid cast expression */
+ error(147);
+ return (NULL);
+ } else if (ot == VOID) {
+ /* improper cast of void expression */
+ error(148);
+ return (NULL);
+ } else if (isityp(nt) && issclt(ot)) {
+ /* ok */
+ } else if (isftyp(nt) && isatyp(ot)) {
+ /* ok */
+ } else if (nt == PTR && isityp(ot)) {
+ /* ok */
+ } else if (nt == PTR && ot == PTR) {
+ if (!tp->t_subt->t_const && tn->tn_type->t_subt->t_const) {
+ if (hflag)
+ /* cast discards 'const' from ... */
+ warning(275);
+ }
+ } else {
+ /* invalid cast expression */
+ error(147);
+ return (NULL);
+ }
+
+ tn = convert(CVT, 0, tp, tn);
+ tn->tn_cast = 1;
+
+ return (tn);
+}
+
+/*
+ * Create the node for a function argument.
+ * All necessary conversions and type checks are done in funccall(), because
+ * in funcarg() we have no information about expected argument types.
+ */
+tnode_t *
+funcarg(args, arg)
+ tnode_t *args, *arg;
+{
+ tnode_t *ntn;
+
+ /*
+ * If there was a serious error in the expression for the argument,
+ * create a dummy argument so the positions of the remaining arguments
+ * will not change.
+ */
+ if (arg == NULL)
+ arg = getinode(INT, (quad_t)0);
+
+ ntn = mktnode(PUSH, arg->tn_type, arg, args);
+
+ return (ntn);
+}
+
+/*
+ * Create the node for a function call. Also check types of
+ * function arguments and insert conversions, if necessary.
+ */
+tnode_t *
+funccall(func, args)
+ tnode_t *func, *args;
+{
+ tnode_t *ntn;
+ op_t fcop;
+
+ if (func == NULL)
+ return (NULL);
+
+ if (func->tn_op == NAME && func->tn_type->t_tspec == FUNC) {
+ fcop = CALL;
+ } else {
+ fcop = ICALL;
+ }
+
+ /*
+ * after cconv() func will always be a pointer to a function
+ * if it is a valid function designator.
+ */
+ func = cconv(func);
+
+ if (func->tn_type->t_tspec != PTR ||
+ func->tn_type->t_subt->t_tspec != FUNC) {
+ /* illegal function */
+ error(149);
+ return (NULL);
+ }
+
+ args = chkfarg(func->tn_type->t_subt, args);
+
+ ntn = mktnode(fcop, func->tn_type->t_subt->t_subt, func, args);
+
+ return (ntn);
+}
+
+/*
+ * Check types of all function arguments and insert conversions,
+ * if necessary.
+ */
+static tnode_t *
+chkfarg(ftp, args)
+ type_t *ftp; /* type of called function */
+ tnode_t *args; /* arguments */
+{
+ tnode_t *arg;
+ sym_t *asym;
+ tspec_t at;
+ int narg, npar, n, i;
+
+ /* get # of args in the prototype */
+ npar = 0;
+ for (asym = ftp->t_args; asym != NULL; asym = asym->s_nxt)
+ npar++;
+
+ /* get # of args in function call */
+ narg = 0;
+ for (arg = args; arg != NULL; arg = arg->tn_right)
+ narg++;
+
+ asym = ftp->t_args;
+ if (ftp->t_proto && npar != narg && !(ftp->t_vararg && npar < narg)) {
+ /* argument mismatch: %d arg%s passed, %d expected */
+ error(150, narg, narg > 1 ? "s" : "", npar);
+ asym = NULL;
+ }
+
+ for (n = 1; n <= narg; n++) {
+
+ /*
+ * The rightmost argument is at the top of the argument
+ * subtree.
+ */
+ for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ;
+
+ /* some things which are always not allowd */
+ if ((at = arg->tn_left->tn_type->t_tspec) == VOID) {
+ /* void expressions may not be arguments, arg #%d */
+ error(151, n);
+ return (NULL);
+ } else if ((at == STRUCT || at == UNION) &&
+ incompl(arg->tn_left->tn_type)) {
+ /* argument cannot have unknown size, arg #%d */
+ error(152, n);
+ return (NULL);
+ } else if (isityp(at) && arg->tn_left->tn_type->t_isenum &&
+ incompl(arg->tn_left->tn_type)) {
+ /* argument cannot have unknown size, arg #%d */
+ warning(152, n);
+ }
+
+ /* class conversions (arg in value context) */
+ arg->tn_left = cconv(arg->tn_left);
+
+ if (asym != NULL) {
+ arg->tn_left = parg(n, asym->s_type, arg->tn_left);
+ } else {
+ arg->tn_left = promote(NOOP, 1, arg->tn_left);
+ }
+ arg->tn_type = arg->tn_left->tn_type;
+
+ if (asym != NULL)
+ asym = asym->s_nxt;
+ }
+
+ return (args);
+}
+
+/*
+ * Compare the type of an argument with the corresponding type of a
+ * prototype parameter. If it is a valid combination, but both types
+ * are not the same, insert a conversion to convert the argument into
+ * the type of the parameter.
+ */
+static tnode_t *
+parg(n, tp, tn)
+ int n; /* pos of arg */
+ type_t *tp; /* expected type (from prototype) */
+ tnode_t *tn; /* argument */
+{
+ tnode_t *ln;
+ int warn;
+
+ ln = xcalloc(1, sizeof (tnode_t));
+ ln->tn_type = tduptyp(tp);
+ ln->tn_type->t_const = 0;
+ ln->tn_lvalue = 1;
+ if (typeok(FARG, n, ln, tn)) {
+ if (!eqtype(tp, tn->tn_type, 1, 0, (warn = 0, &warn)) || warn)
+ tn = convert(FARG, n, tp, tn);
+ }
+ free(ln);
+ return (tn);
+}
+
+/*
+ * Return the value of an integral constant expression.
+ * If the expression is not constant or its type is not an integer
+ * type, an error message is printed.
+ */
+val_t *
+constant(tn)
+ tnode_t *tn;
+{
+ val_t *v;
+
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+
+ v = xcalloc(1, sizeof (val_t));
+
+ if (tn == NULL) {
+ if (nerr == 0)
+ lerror("constant() 1");
+ v->v_tspec = INT;
+ v->v_quad = 1;
+ return (v);
+ }
+
+ v->v_tspec = tn->tn_type->t_tspec;
+
+ if (tn->tn_op == CON) {
+ if (tn->tn_type->t_tspec != tn->tn_val->v_tspec)
+ lerror("constant() 2");
+ if (isityp(tn->tn_val->v_tspec)) {
+ v->v_ansiu = tn->tn_val->v_ansiu;
+ v->v_quad = tn->tn_val->v_quad;
+ return (v);
+ }
+ v->v_quad = tn->tn_val->v_ldbl;
+ } else {
+ v->v_quad = 1;
+ }
+
+ /* integral constant expression expected */
+ error(55);
+
+ if (!isityp(v->v_tspec))
+ v->v_tspec = INT;
+
+ return (v);
+}
+
+/*
+ * Perform some tests on expressions which can't be done in build() and
+ * functions called by build(). These tests must be done here because
+ * we need some information about the context in which the operations
+ * are performed.
+ * After all tests are performed, expr() frees the memory which is used
+ * for the expression.
+ */
+void
+expr(tn, vctx, tctx)
+ tnode_t *tn;
+ int vctx, tctx;
+{
+ if (tn == NULL && nerr == 0)
+ lerror("expr() 1");
+
+ if (tn == NULL) {
+ tfreeblk();
+ return;
+ }
+
+ /* expr() is also called in global initialisations */
+ if (dcs->d_ctx != EXTERN)
+ chkreach();
+
+ chkmisc(tn, vctx, tctx, !tctx, 0, 0, 0);
+ if (tn->tn_op == ASSIGN) {
+ if (hflag && tctx)
+ /* assignment in conditional context */
+ warning(159);
+ } else if (tn->tn_op == CON) {
+ if (hflag && tctx && !ccflg)
+ /* constant in conditional context */
+ warning(161);
+ }
+ if (!modtab[tn->tn_op].m_sideeff) {
+ /*
+ * for left operands of COMMA this warning is already
+ * printed
+ */
+ if (tn->tn_op != COMMA && !vctx && !tctx)
+ nulleff(tn);
+ }
+ if (dflag)
+ displexpr(tn, 0);
+
+ /* free the tree memory */
+ tfreeblk();
+}
+
+static void
+nulleff(tn)
+ tnode_t *tn;
+{
+ if (!hflag)
+ return;
+
+ while (!modtab[tn->tn_op].m_sideeff) {
+ if (tn->tn_op == CVT && tn->tn_type->t_tspec == VOID) {
+ tn = tn->tn_left;
+ } else if (tn->tn_op == LOGAND || tn->tn_op == LOGOR) {
+ /*
+ * && and || have a side effect if the right operand
+ * has a side effect.
+ */
+ tn = tn->tn_right;
+ } else if (tn->tn_op == QUEST) {
+ /*
+ * ? has a side effect if at least one of its right
+ * operands has a side effect
+ */
+ tn = tn->tn_right;
+ } else if (tn->tn_op == COLON) {
+ /*
+ * : has a side effect if at least one of its operands
+ * has a side effect
+ */
+ if (modtab[tn->tn_left->tn_op].m_sideeff) {
+ tn = tn->tn_left;
+ } else if (modtab[tn->tn_right->tn_op].m_sideeff) {
+ tn = tn->tn_right;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ if (!modtab[tn->tn_op].m_sideeff)
+ /* expression has null effect */
+ warning(129);
+}
+
+/*
+ * Dump an expression to stdout
+ * only used for debugging
+ */
+static void
+displexpr(tn, offs)
+ tnode_t *tn;
+ int offs;
+{
+ u_quad_t uq;
+
+ if (tn == NULL) {
+ (void)printf("%*s%s\n", offs, "", "NULL");
+ return;
+ }
+ (void)printf("%*sop %s ", offs, "", modtab[tn->tn_op].m_name);
+
+ if (tn->tn_op == NAME) {
+ (void)printf("%s: %s ",
+ tn->tn_sym->s_name, scltoa(tn->tn_sym->s_scl));
+ } else if (tn->tn_op == CON && isftyp(tn->tn_type->t_tspec)) {
+ (void)printf("%#g ", (double)tn->tn_val->v_ldbl);
+ } else if (tn->tn_op == CON && isityp(tn->tn_type->t_tspec)) {
+ uq = tn->tn_val->v_quad;
+ (void)printf("0x %08lx %08lx ", (long)(uq >> 32) & 0xffffffffl,
+ (long)uq & 0xffffffffl);
+ } else if (tn->tn_op == CON) {
+ if (tn->tn_type->t_tspec != PTR)
+ lerror("displexpr() 1");
+ (void)printf("0x%0*lx ", (int)(sizeof (void *) * CHAR_BIT / 4),
+ (u_long)tn->tn_val->v_quad);
+ } else if (tn->tn_op == STRING) {
+ if (tn->tn_strg->st_tspec == CHAR) {
+ (void)printf("\"%s\"", tn->tn_strg->st_cp);
+ } else {
+ char *s;
+ size_t n;
+ n = MB_CUR_MAX * (tn->tn_strg->st_len + 1);
+ s = xmalloc(n);
+ (void)wcstombs(s, tn->tn_strg->st_wcp, n);
+ (void)printf("L\"%s\"", s);
+ free(s);
+ }
+ (void)printf(" ");
+ } else if (tn->tn_op == FSEL) {
+ (void)printf("o=%d, l=%d ", tn->tn_type->t_foffs,
+ tn->tn_type->t_flen);
+ }
+ (void)printf("%s\n", ttos(tn->tn_type));
+ if (tn->tn_op == NAME || tn->tn_op == CON || tn->tn_op == STRING)
+ return;
+ displexpr(tn->tn_left, offs + 2);
+ if (modtab[tn->tn_op].m_binary ||
+ (tn->tn_op == PUSH && tn->tn_right != NULL)) {
+ displexpr(tn->tn_right, offs + 2);
+ }
+}
+
+/*
+ * Called by expr() to recursively perform some tests.
+ */
+/* ARGSUSED */
+void
+chkmisc(tn, vctx, tctx, eqwarn, fcall, rvdisc, szof)
+ tnode_t *tn;
+ int vctx, tctx, eqwarn, fcall, rvdisc, szof;
+{
+ tnode_t *ln, *rn;
+ mod_t *mp;
+ int nrvdisc, cvctx, ctctx;
+ op_t op;
+ scl_t sc;
+ dinfo_t *di;
+
+ if (tn == NULL)
+ return;
+
+ ln = tn->tn_left;
+ rn = tn->tn_right;
+ mp = &modtab[op = tn->tn_op];
+
+ switch (op) {
+ case AMPER:
+ if (ln->tn_op == NAME && (reached || rchflg)) {
+ if (!szof)
+ setsflg(ln->tn_sym);
+ setuflg(ln->tn_sym, fcall, szof);
+ }
+ if (ln->tn_op == STAR && ln->tn_left->tn_op == PLUS)
+ /* check the range of array indices */
+ chkaidx(ln->tn_left, 1);
+ break;
+ case LOAD:
+ if (ln->tn_op == STAR && ln->tn_left->tn_op == PLUS)
+ /* check the range of array indices */
+ chkaidx(ln->tn_left, 0);
+ /* FALLTHROUGH */
+ case PUSH:
+ case INCBEF:
+ case DECBEF:
+ case INCAFT:
+ case DECAFT:
+ case ADDASS:
+ case SUBASS:
+ case MULASS:
+ case DIVASS:
+ case MODASS:
+ case ANDASS:
+ case ORASS:
+ case XORASS:
+ case SHLASS:
+ case SHRASS:
+ if (ln->tn_op == NAME && (reached || rchflg)) {
+ sc = ln->tn_sym->s_scl;
+ /*
+ * Look if there was a asm statement in one of the
+ * compound statements we are in. If not, we don't
+ * print a warning.
+ */
+ for (di = dcs; di != NULL; di = di->d_nxt) {
+ if (di->d_asm)
+ break;
+ }
+ if (sc != EXTERN && sc != STATIC &&
+ !ln->tn_sym->s_set && !szof && di == NULL) {
+ /* %s may be used before set */
+ warning(158, ln->tn_sym->s_name);
+ setsflg(ln->tn_sym);
+ }
+ setuflg(ln->tn_sym, 0, 0);
+ }
+ break;
+ case ASSIGN:
+ if (ln->tn_op == NAME && !szof && (reached || rchflg)) {
+ setsflg(ln->tn_sym);
+ if (ln->tn_sym->s_scl == EXTERN)
+ outusg(ln->tn_sym);
+ }
+ if (ln->tn_op == STAR && ln->tn_left->tn_op == PLUS)
+ /* check the range of array indices */
+ chkaidx(ln->tn_left, 0);
+ break;
+ case CALL:
+ if (ln->tn_op != AMPER || ln->tn_left->tn_op != NAME)
+ lerror("chkmisc() 1");
+ if (!szof)
+ outcall(tn, vctx || tctx, rvdisc);
+ break;
+ case EQ:
+ /* equality operator "==" found where "=" was exp. */
+ if (hflag && eqwarn)
+ warning(160);
+ break;
+ case CON:
+ case NAME:
+ case STRING:
+ return;
+ /* LINTED (enumeration values not handled in switch) */
+ }
+
+ cvctx = mp->m_vctx;
+ ctctx = mp->m_tctx;
+ /*
+ * values of operands of ':' are not used if the type of at least
+ * one of the operands (for gcc compatibility) is void
+ * XXX test/value context of QUEST should probably be used as
+ * context for both operands of COLON
+ */
+ if (op == COLON && tn->tn_type->t_tspec == VOID)
+ cvctx = ctctx = 0;
+ nrvdisc = op == CVT && tn->tn_type->t_tspec == VOID;
+ chkmisc(ln, cvctx, ctctx, mp->m_eqwarn, op == CALL, nrvdisc, szof);
+
+ switch (op) {
+ case PUSH:
+ if (rn != NULL)
+ chkmisc(rn, 0, 0, mp->m_eqwarn, 0, 0, szof);
+ break;
+ case LOGAND:
+ case LOGOR:
+ chkmisc(rn, 0, 1, mp->m_eqwarn, 0, 0, szof);
+ break;
+ case COLON:
+ chkmisc(rn, cvctx, ctctx, mp->m_eqwarn, 0, 0, szof);
+ break;
+ default:
+ if (mp->m_binary)
+ chkmisc(rn, 1, 0, mp->m_eqwarn, 0, 0, szof);
+ break;
+ }
+
+}
+
+/*
+ * Checks the range of array indices, if possible.
+ * amper is set if only the address of the element is used. This
+ * means that the index is allowd to refere to the first element
+ * after the array.
+ */
+static void
+chkaidx(tn, amper)
+ tnode_t *tn;
+ int amper;
+{
+ int dim;
+ tnode_t *ln, *rn;
+ int elsz;
+ quad_t con;
+
+ ln = tn->tn_left;
+ rn = tn->tn_right;
+
+ /* We can only check constant indices. */
+ if (rn->tn_op != CON)
+ return;
+
+ /* Return if the left node does not stem from an array. */
+ if (ln->tn_op != AMPER)
+ return;
+ if (ln->tn_left->tn_op != STRING && ln->tn_left->tn_op != NAME)
+ return;
+ if (ln->tn_left->tn_type->t_tspec != ARRAY)
+ return;
+
+ /*
+ * For incomplete array types, we can print a warning only if
+ * the index is negative.
+ */
+ if (incompl(ln->tn_left->tn_type) && rn->tn_val->v_quad >= 0)
+ return;
+
+ /* Get the size of one array element */
+ if ((elsz = length(ln->tn_type->t_subt, NULL)) == 0)
+ return;
+ elsz /= CHAR_BIT;
+
+ /* Change the unit of the index from bytes to element size. */
+ if (isutyp(rn->tn_type->t_tspec)) {
+ con = (u_quad_t)rn->tn_val->v_quad / elsz;
+ } else {
+ con = rn->tn_val->v_quad / elsz;
+ }
+
+ dim = ln->tn_left->tn_type->t_dim + (amper ? 1 : 0);
+
+ if (!isutyp(rn->tn_type->t_tspec) && con < 0) {
+ /* array subscript cannot be negative: %ld */
+ warning(167, (long)con);
+ } else if (dim > 0 && (u_quad_t)con >= dim) {
+ /* array subscript cannot be > %d: %ld */
+ warning(168, dim - 1, (long)con);
+ }
+}
+
+/*
+ * Check for ordered comparisions of unsigned values with 0.
+ */
+static void
+chkcomp(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tspec_t lt, rt;
+ mod_t *mp;
+
+ lt = ln->tn_type->t_tspec;
+ rt = rn->tn_type->t_tspec;
+ mp = &modtab[op];
+
+ if (ln->tn_op != CON && rn->tn_op != CON)
+ return;
+
+ if (!isityp(lt) || !isityp(rt))
+ return;
+
+ if ((hflag || pflag) && lt == CHAR && rn->tn_op == CON &&
+ (rn->tn_val->v_quad < 0 ||
+ rn->tn_val->v_quad > ~(~0 << (CHAR_BIT - 1)))) {
+ /* nonportable character comparision, op %s */
+ warning(230, mp->m_name);
+ return;
+ }
+ if ((hflag || pflag) && rt == CHAR && ln->tn_op == CON &&
+ (ln->tn_val->v_quad < 0 ||
+ ln->tn_val->v_quad > ~(~0 << (CHAR_BIT - 1)))) {
+ /* nonportable character comparision, op %s */
+ warning(230, mp->m_name);
+ return;
+ }
+ if (isutyp(lt) && !isutyp(rt) &&
+ rn->tn_op == CON && rn->tn_val->v_quad <= 0) {
+ if (rn->tn_val->v_quad < 0) {
+ /* comparision of %s with %s, op %s */
+ warning(162, tyname(ln->tn_type), "negative constant",
+ mp->m_name);
+ } else if (op == LT || op == GE || (hflag && op == LE)) {
+ /* comparision of %s with %s, op %s */
+ warning(162, tyname(ln->tn_type), "0", mp->m_name);
+ }
+ return;
+ }
+ if (isutyp(rt) && !isutyp(lt) &&
+ ln->tn_op == CON && ln->tn_val->v_quad <= 0) {
+ if (ln->tn_val->v_quad < 0) {
+ /* comparision of %s with %s, op %s */
+ warning(162, "negative constant", tyname(rn->tn_type),
+ mp->m_name);
+ } else if (op == GT || op == LE || (hflag && op == GE)) {
+ /* comparision of %s with %s, op %s */
+ warning(162, "0", tyname(rn->tn_type), mp->m_name);
+ }
+ return;
+ }
+}
+
+/*
+ * Takes an expression an returns 0 if this expression can be used
+ * for static initialisation, otherwise -1.
+ *
+ * Constant initialisation expressions must be costant or an address
+ * of a static object with an optional offset. In the first case,
+ * the result is returned in *offsp. In the second case, the static
+ * object is returned in *symp and the offset in *offsp.
+ *
+ * The expression can consist of PLUS, MINUS, AMPER, NAME, STRING and
+ * CON. Type conversions are allowed if they do not change binary
+ * representation (including width).
+ */
+int
+conaddr(tn, symp, offsp)
+ tnode_t *tn;
+ sym_t **symp;
+ ptrdiff_t *offsp;
+{
+ sym_t *sym;
+ ptrdiff_t offs1, offs2;
+ tspec_t t, ot;
+
+ switch (tn->tn_op) {
+ case MINUS:
+ if (tn->tn_right->tn_op != CON)
+ return (-1);
+ /* FALLTHROUGH */
+ case PLUS:
+ offs1 = offs2 = 0;
+ if (tn->tn_left->tn_op == CON) {
+ offs1 = (ptrdiff_t)tn->tn_left->tn_val->v_quad;
+ if (conaddr(tn->tn_right, &sym, &offs2) == -1)
+ return (-1);
+ } else if (tn->tn_right->tn_op == CON) {
+ offs2 = (ptrdiff_t)tn->tn_right->tn_val->v_quad;
+ if (tn->tn_op == MINUS)
+ offs2 = -offs2;
+ if (conaddr(tn->tn_left, &sym, &offs1) == -1)
+ return (-1);
+ } else {
+ return (-1);
+ }
+ *symp = sym;
+ *offsp = offs1 + offs2;
+ break;
+ case AMPER:
+ if (tn->tn_left->tn_op == NAME) {
+ *symp = tn->tn_left->tn_sym;
+ *offsp = 0;
+ } else if (tn->tn_left->tn_op == STRING) {
+ /*
+ * If this would be the front end of a compiler we
+ * would return a label instead of 0.
+ */
+ *offsp = 0;
+ }
+ break;
+ case CVT:
+ t = tn->tn_type->t_tspec;
+ ot = tn->tn_left->tn_type->t_tspec;
+ if ((!isityp(t) && t != PTR) || (!isityp(ot) && ot != PTR)) {
+ return (-1);
+ } else if (psize(t) != psize(ot)) {
+ return (-1);
+ }
+ if (conaddr(tn->tn_left, symp, offsp) == -1)
+ return (-1);
+ break;
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Concatenate two string constants.
+ */
+strg_t *
+catstrg(strg1, strg2)
+ strg_t *strg1, *strg2;
+{
+ size_t len1, len2, len;
+
+ if (strg1->st_tspec != strg2->st_tspec) {
+ /* cannot concatenate wide and regular string literals */
+ error(292);
+ return (strg1);
+ }
+
+ len = (len1 = strg1->st_len) + (len2 = strg2->st_len);
+
+ if (strg1->st_tspec == CHAR) {
+ strg1->st_cp = xrealloc(strg1->st_cp, len + 1);
+ (void)memcpy(strg1->st_cp + len1, strg2->st_cp, len2 + 1);
+ free(strg2->st_cp);
+ } else {
+ strg1->st_wcp = xrealloc(strg1->st_wcp,
+ (len + 1) * sizeof (wchar_t));
+ (void)memcpy(strg1->st_wcp + len1, strg2->st_wcp,
+ (len2 + 1) * sizeof (wchar_t));
+ free(strg2->st_wcp);
+ }
+ free(strg2);
+
+ return (strg1);
+}
+
+/*
+ * Print a warning if the given node has operands which should be
+ * parenthesized.
+ *
+ * XXX Does not work if an operand is a constant expression. Constant
+ * expressions are already folded.
+ */
+static void
+precconf(tn)
+ tnode_t *tn;
+{
+ tnode_t *ln, *rn;
+ op_t lop, rop;
+ int lparn, rparn;
+ mod_t *mp;
+ int warn;
+
+ if (!hflag)
+ return;
+
+ mp = &modtab[tn->tn_op];
+
+ lparn = 0;
+ for (ln = tn->tn_left; ln->tn_op == CVT; ln = ln->tn_left)
+ lparn |= ln->tn_parn;
+ lparn |= ln->tn_parn;
+ lop = ln->tn_op;
+
+ if (mp->m_binary) {
+ rparn = 0;
+ for (rn = tn->tn_right; tn->tn_op == CVT; rn = rn->tn_left)
+ rparn |= rn->tn_parn;
+ rparn |= rn->tn_parn;
+ rop = rn->tn_op;
+ }
+
+ warn = 0;
+
+ switch (tn->tn_op) {
+ case SHL:
+ case SHR:
+ if (!lparn && (lop == PLUS || lop == MINUS)) {
+ warn = 1;
+ } else if (!rparn && (rop == PLUS || rop == MINUS)) {
+ warn = 1;
+ }
+ break;
+ case LOGOR:
+ if (!lparn && lop == LOGAND) {
+ warn = 1;
+ } else if (!rparn && rop == LOGAND) {
+ warn = 1;
+ }
+ break;
+ case AND:
+ case XOR:
+ case OR:
+ if (!lparn && lop != tn->tn_op) {
+ if (lop == PLUS || lop == MINUS) {
+ warn = 1;
+ } else if (lop == AND || lop == XOR) {
+ warn = 1;
+ }
+ }
+ if (!warn && !rparn && rop != tn->tn_op) {
+ if (rop == PLUS || rop == MINUS) {
+ warn = 1;
+ } else if (rop == AND || rop == XOR) {
+ warn = 1;
+ }
+ }
+ break;
+ /* LINTED (enumeration values not handled in switch) */
+ }
+
+ if (warn) {
+ /* precedence confusion possible: parenthesize! */
+ warning(169);
+ }
+
+}
OpenPOWER on IntegriCloud