scan.l revision 223262
1218893Sdim%{
2193323Sed/* $NetBSD: scan.l,v 1.26 2002/01/31 22:30:21 tv Exp $ */
3193323Sed
4193323Sed/*
5193323Sed * Copyright (c) 1996 Christopher G. Demetriou.  All Rights Reserved.
6193323Sed * Copyright (c) 1994, 1995 Jochen Pohl
7193323Sed * All Rights Reserved.
8193323Sed *
9193323Sed * Redistribution and use in source and binary forms, with or without
10218893Sdim * modification, are permitted provided that the following conditions
11218893Sdim * are met:
12218893Sdim * 1. Redistributions of source code must retain the above copyright
13193323Sed *    notice, this list of conditions and the following disclaimer.
14193323Sed * 2. Redistributions in binary form must reproduce the above copyright
15193323Sed *    notice, this list of conditions and the following disclaimer in the
16296417Sdim *    documentation and/or other materials provided with the distribution.
17249423Sdim * 3. All advertising materials mentioning features or use of this software
18296417Sdim *    must display the following acknowledgement:
19193323Sed *      This product includes software developed by Jochen Pohl for
20276479Sdim *      The NetBSD Project.
21199989Srdivacky * 4. The name of the author may not be used to endorse or promote products
22249423Sdim *    derived from this software without specific prior written permission.
23265925Sdim *
24199989Srdivacky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25199989Srdivacky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26296417Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27249423Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28249423Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29249423Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30276479Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31249423Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32249423Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33249423Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34249423Sdim */
35249423Sdim
36249423Sdim#include <sys/cdefs.h>
37249423Sdim#if defined(__RCSID) && !defined(lint)
38198090Srdivacky__RCSID("$NetBSD: scan.l,v 1.26 2002/01/31 22:30:21 tv Exp $");
39193323Sed#endif
40193323Sed__FBSDID("$FreeBSD: head/usr.bin/xlint/lint1/scan.l 223262 2011-06-18 13:56:33Z benl $");
41193323Sed
42296417Sdim#include <stdlib.h>
43296417Sdim#include <string.h>
44296417Sdim#include <limits.h>
45296417Sdim#include <float.h>
46296417Sdim#include <ctype.h>
47296417Sdim#include <errno.h>
48296417Sdim#include <err.h>
49296417Sdim#include <math.h>
50296417Sdim
51296417Sdim#include "lint1.h"
52296417Sdim#include "cgram.h"
53296417Sdim
54265925Sdim#define CHAR_MASK	(~(~0 << CHAR_BIT))
55265925Sdim#define YY_NO_UNPUT
56265925Sdim
57265925Sdim/* Current position (its also updated when an included file is parsed) */
58265925Sdimpos_t	curr_pos = { 1, "", 0 };
59265925Sdim
60276479Sdim/*
61276479Sdim * Current position in C source (not updated when an included file is
62276479Sdim * parsed).
63276479Sdim */
64276479Sdimpos_t	csrc_pos = { 1, "", 0 };
65193323Sed
66193323Sedstatic	void	incline(void);
67193323Sedstatic	void	badchar(int);
68193323Sedstatic	sbuf_t	*allocsb(void);
69296417Sdimstatic	void	freesb(sbuf_t *);
70296417Sdimstatic	int	inpc(void);
71193323Sedstatic	int	hash(const char *);
72193323Sedstatic	sym_t	*search(sbuf_t *);
73198892Srdivackystatic	int	name(void);
74199989Srdivackystatic	int	keyw(sym_t *);
75199989Srdivackystatic	int	icon(int);
76199989Srdivackystatic	int	fcon(void);
77199989Srdivackystatic	int	operator(int, op_t);
78199989Srdivackystatic	int	ccon(void);
79199989Srdivackystatic	int	wccon(void);
80193323Sedstatic	int	getescc(int);
81193323Sedstatic	void	directive(void);
82193323Sedstatic	void	comment(void);
83193323Sedstatic	void	slashslashcomment(void);
84193323Sedstatic	int	string(void);
85243830Sdimstatic	int	wcstrg(void);
86243830Sdim
87243830Sdim%}
88243830Sdim
89199989SrdivackyL	[_A-Za-z]
90243830SdimD	[0-9]
91193323SedNZD	[1-9]
92193323SedOD	[0-7]
93193323SedHD	[0-9A-Fa-f]
94296417SdimEX	([eE][+-]?[0-9]+)
95296417Sdim
96210299Sed%%
97210299Sed
98210299Sed{L}({L}|{D})*		 	return (name());
99193323Sed0{OD}*[lLuU]*			return (icon(8));
100210299Sed{NZD}{D}*[lLuU]*		return (icon(10));
101210299Sed0[xX]{HD}+[lLuU]*		return (icon(16));
102210299Sed{D}+\.{D}*{EX}?[fFlL]?		|
103210299Sed{D}+{EX}[fFlL]?			|
104210299Sed\.{D}+{EX}?[fFlL]?		return (fcon());
105210299Sed"="				return (operator(T_ASSIGN, ASSIGN));
106210299Sed"*="				return (operator(T_OPASS, MULASS));
107210299Sed"/="				return (operator(T_OPASS, DIVASS));
108210299Sed"%="				return (operator(T_OPASS, MODASS));
109296417Sdim"+="				return (operator(T_OPASS, ADDASS));
110276479Sdim"-="				return (operator(T_OPASS, SUBASS));
111243830Sdim"<<="				return (operator(T_OPASS, SHLASS));
112234353Sdim">>="				return (operator(T_OPASS, SHRASS));
113239462Sdim"&="				return (operator(T_OPASS, ANDASS));
114288943Sdim"^="				return (operator(T_OPASS, XORASS));
115239462Sdim"|="				return (operator(T_OPASS, ORASS));
116288943Sdim"||"				return (operator(T_LOGOR, LOGOR));
117193323Sed"&&"				return (operator(T_LOGAND, LOGAND));
118193323Sed"|"				return (operator(T_OR, OR));
119296417Sdim"&"				return (operator(T_AND, AND));
120296417Sdim"^"				return (operator(T_XOR, XOR));
121218893Sdim"=="				return (operator(T_EQOP, EQ));
122276479Sdim"!="				return (operator(T_EQOP, NE));
123243830Sdim"<"				return (operator(T_RELOP, LT));
124251662Sdim">"				return (operator(T_RELOP, GT));
125251662Sdim"<="				return (operator(T_RELOP, LE));
126251662Sdim">="				return (operator(T_RELOP, GE));
127251662Sdim"<<"				return (operator(T_SHFTOP, SHL));
128251662Sdim">>"				return (operator(T_SHFTOP, SHR));
129251662Sdim"++"				return (operator(T_INCDEC, INC));
130251662Sdim"--"				return (operator(T_INCDEC, DEC));
131251662Sdim"->"				return (operator(T_STROP, ARROW));
132251662Sdim"."				return (operator(T_STROP, POINT));
133251662Sdim"+"				return (operator(T_ADDOP, PLUS));
134251662Sdim"-"				return (operator(T_ADDOP, MINUS));
135251662Sdim"*"				return (operator(T_MULT, MULT));
136251662Sdim"/"				return (operator(T_DIVOP, DIV));
137251662Sdim"%"				return (operator(T_DIVOP, MOD));
138251662Sdim"!"				return (operator(T_UNOP, NOT));
139251662Sdim"~"				return (operator(T_UNOP, COMPL));
140251662Sdim"\""				return (string());
141251662Sdim"L\""				return (wcstrg());
142251662Sdim";"				return (T_SEMI);
143251662Sdim"{"				return (T_LBRACE);
144251662Sdim"}"				return (T_RBRACE);
145251662Sdim","				return (T_COMMA);
146251662Sdim":"				return (T_COLON);
147251662Sdim"?"				return (T_QUEST);
148261991Sdim"["				return (T_LBRACK);
149251662Sdim"]"				return (T_RBRACK);
150251662Sdim"("				return (T_LPARN);
151251662Sdim")"				return (T_RPARN);
152251662Sdim"..."				return (T_ELLIPSE);
153234353Sdim"'"				return (ccon());
154234353Sdim"L'"				return (wccon());
155296417Sdim^#.*$				directive();
156261991Sdim\n				incline();
157288943Sdim\t|" "|\f|\v			;
158218893Sdim"/*"				comment();
159193323Sed"//"				slashslashcomment();
160296417Sdim.				badchar(yytext[0]);
161296417Sdim
162296417Sdim%%
163276479Sdim
164288943Sdimstatic void
165218893Sdimincline(void)
166193323Sed{
167193323Sed	curr_pos.p_line++;
168212904Sdim	curr_pos.p_uniq = 0;
169212904Sdim	if (curr_pos.p_file == csrc_pos.p_file) {
170212904Sdim		csrc_pos.p_line++;
171296417Sdim		csrc_pos.p_uniq = 0;
172296417Sdim	}
173212904Sdim}
174296417Sdim
175296417Sdimstatic void
176296417Sdimbadchar(int c)
177296417Sdim{
178296417Sdim
179212904Sdim	/* unknown character \%o */
180212904Sdim	error(250, c);
181296417Sdim}
182296417Sdim
183296417Sdim/*
184296417Sdim * Keywords.
185212904Sdim * During initialisation they are written to the symbol table.
186212904Sdim */
187212904Sdimstatic	struct	kwtab {
188212904Sdim	const	char *kw_name;	/* keyword */
189212904Sdim	int	kw_token;	/* token returned by yylex() */
190212904Sdim	scl_t	kw_scl;		/* storage class if kw_token T_SCLASS */
191212904Sdim	tspec_t	kw_tspec;	/* type spec. if kw_token T_TYPE or T_SOU */
192212904Sdim	tqual_t	kw_tqual;	/* type qual. fi kw_token T_QUAL */
193261991Sdim	u_int	kw_stdc : 1;	/* STDC keyword */
194296417Sdim	u_int	kw_gcc : 1;	/* GCC keyword */
195296417Sdim} kwtab[] = {
196296417Sdim	{ "asm",	T_ASM,		0,	0,	0,	  0, 1 },
197296417Sdim	{ "__asm",	T_ASM,		0,	0,	0,	  0, 0 },
198296417Sdim	{ "__asm__",	T_ASM,		0,	0,	0,	  0, 0 },
199296417Sdim	{ "auto",	T_SCLASS,	AUTO,	0,	0,	  0, 0 },
200296417Sdim	{ "break",	T_BREAK,	0,	0,	0,	  0, 0 },
201296417Sdim	{ "case",	T_CASE,		0,	0,	0,	  0, 0 },
202296417Sdim	{ "char",	T_TYPE,		0,	CHAR,	0,	  0, 0 },
203296417Sdim	{ "const",	T_QUAL,		0,	0,	CONST,	  1, 0 },
204296417Sdim	{ "__const__",	T_QUAL,		0,	0,	CONST,	  0, 0 },
205296417Sdim	{ "__const",	T_QUAL,		0,	0,	CONST,	  0, 0 },
206212904Sdim	{ "continue",	T_CONTINUE,	0,	0,	0,	  0, 0 },
207296417Sdim	{ "default",	T_DEFAULT,	0,	0,	0,	  0, 0 },
208296417Sdim	{ "do",		T_DO,		0,	0,	0,	  0, 0 },
209296417Sdim	{ "double",	T_TYPE,		0,	DOUBLE,	0,	  0, 0 },
210296417Sdim	{ "else",	T_ELSE,		0,	0,	0,	  0, 0 },
211296417Sdim	{ "enum",	T_ENUM,		0,	0,	0,	  0, 0 },
212296417Sdim	{ "extern",	T_SCLASS,	EXTERN,	0,	0,	  0, 0 },
213212904Sdim	{ "float",	T_TYPE,		0,	FLOAT,	0,	  0, 0 },
214296417Sdim	{ "for",	T_FOR,		0,	0,	0,	  0, 0 },
215296417Sdim	{ "goto",	T_GOTO,		0,	0,	0,	  0, 0 },
216296417Sdim	{ "if",		T_IF,		0,	0,	0,	  0, 0 },
217296417Sdim	{ "inline",	T_SCLASS,	INLINE,	0,	0,	  0, 1 },
218296417Sdim	{ "__inline__",	T_SCLASS,	INLINE,	0,	0,	  0, 0 },
219296417Sdim	{ "__inline",	T_SCLASS,	INLINE,	0,	0,	  0, 0 },
220212904Sdim	{ "int",	T_TYPE,		0,	INT,	0,	  0, 0 },
221212904Sdim	{ "__symbolrename", T_SYMBOLRENAME, 0,	0,	0,	  0, 0 },
222212904Sdim	{ "long",	T_TYPE,		0,	LONG,	0,	  0, 0 },
223288943Sdim	{ "register",	T_SCLASS,	REG,	0,	0,	  0, 0 },
224296417Sdim	{ "return",	T_RETURN,	0,	0,	0,	  0, 0 },
225296417Sdim	{ "short",	T_TYPE,		0,	SHORT,	0,	  0, 0 },
226296417Sdim	{ "signed",	T_TYPE,		0,	SIGNED,	0,	  1, 0 },
227296417Sdim	{ "__signed__",	T_TYPE,		0,	SIGNED,	0,	  0, 0 },
228296417Sdim	{ "__signed",	T_TYPE,		0,	SIGNED,	0,	  0, 0 },
229296417Sdim	{ "sizeof",	T_SIZEOF,	0,	0,	0,	  0, 0 },
230212904Sdim	{ "static",	T_SCLASS,	STATIC,	0,	0,	  0, 0 },
231296417Sdim	{ "struct",	T_SOU,		0,	STRUCT,	0,	  0, 0 },
232296417Sdim	{ "switch",	T_SWITCH,	0,	0,	0,	  0, 0 },
233296417Sdim	{ "typedef",	T_SCLASS,	TYPEDEF, 0,	0,	  0, 0 },
234296417Sdim	{ "union",	T_SOU,		0,	UNION,	0,	  0, 0 },
235296417Sdim	{ "unsigned",	T_TYPE,		0,	UNSIGN,	0,	  0, 0 },
236296417Sdim	{ "void",	T_TYPE,		0,	VOID,	0,	  0, 0 },
237296417Sdim	{ "volatile",	T_QUAL,		0,	0,	VOLATILE, 1, 0 },
238296417Sdim	{ "__volatile__", T_QUAL,	0,	0,	VOLATILE, 0, 0 },
239296417Sdim	{ "__volatile",	T_QUAL,		0,	0,	VOLATILE, 0, 0 },
240212904Sdim	{ "while",	T_WHILE,	0,	0,	0,	  0, 0 },
241296417Sdim	{ NULL,		0,		0,	0,	0,	  0, 0 }
242296417Sdim};
243296417Sdim
244296417Sdim/* Symbol table */
245296417Sdimstatic	sym_t	*symtab[HSHSIZ1];
246212904Sdim
247296417Sdim/* bit i of the entry with index i is set */
248296417Sdimuint64_t qbmasks[sizeof(uint64_t) * CHAR_BIT];
249296417Sdim
250296417Sdim/* least significant i bits are set in the entry with index i */
251296417Sdimuint64_t qlmasks[sizeof(uint64_t) * CHAR_BIT + 1];
252296417Sdim
253296417Sdim/* least significant i bits are not set in the entry with index i */
254212904Sdimuint64_t qumasks[sizeof(uint64_t) * CHAR_BIT + 1];
255212904Sdim
256296417Sdim/* free list for sbuf structures */
257296417Sdimstatic	sbuf_t	 *sbfrlst;
258296417Sdim
259296417Sdim/* Typ of next expected symbol */
260296417Sdimsymt_t	symtyp;
261296417Sdim
262212904Sdim
263212904Sdim/*
264261991Sdim * All keywords are written to the symbol table. This saves us looking
265212904Sdim * in an extra table for each name we found.
266212904Sdim */
267212904Sdimvoid
268296417Sdiminitscan(void)
269212904Sdim{
270296417Sdim	struct	kwtab *kw;
271212904Sdim	sym_t	*sym;
272296417Sdim	int	h, i;
273296417Sdim	uint64_t uq;
274296417Sdim
275296417Sdim	for (kw = kwtab; kw->kw_name != NULL; kw++) {
276212904Sdim		if (kw->kw_stdc && tflag)
277296417Sdim			continue;
278296417Sdim		if (kw->kw_gcc && !gflag)
279296417Sdim			continue;
280261991Sdim		sym = getblk(sizeof (sym_t));
281296417Sdim		sym->s_name = kw->kw_name;
282296417Sdim		sym->s_keyw = 1;
283296417Sdim		sym->s_value.v_quad = kw->kw_token;
284296417Sdim		if (kw->kw_token == T_TYPE || kw->kw_token == T_SOU) {
285296417Sdim			sym->s_tspec = kw->kw_tspec;
286296417Sdim		} else if (kw->kw_token == T_SCLASS) {
287296417Sdim			sym->s_scl = kw->kw_scl;
288296417Sdim		} else if (kw->kw_token == T_QUAL) {
289296417Sdim			sym->s_tqual = kw->kw_tqual;
290296417Sdim		}
291296417Sdim		h = hash(sym->s_name);
292296417Sdim		if ((sym->s_link = symtab[h]) != NULL)
293296417Sdim			symtab[h]->s_rlink = &sym->s_link;
294296417Sdim		(symtab[h] = sym)->s_rlink = &symtab[h];
295296417Sdim	}
296296417Sdim
297296417Sdim	/* initialize bit-masks for quads */
298296417Sdim	for (i = 0; i < sizeof (uint64_t) * CHAR_BIT; i++) {
299296417Sdim		qbmasks[i] = (uint64_t)1 << i;
300296417Sdim		uq = ~(uint64_t)0 << i;
301296417Sdim		qumasks[i] = uq;
302296417Sdim		qlmasks[i] = ~uq;
303296417Sdim	}
304296417Sdim	qumasks[i] = 0;
305296417Sdim	qlmasks[i] = ~(uint64_t)0;
306296417Sdim}
307296417Sdim
308296417Sdim/*
309296417Sdim * Get a free sbuf structure, if possible from the free list
310296417Sdim */
311296417Sdimstatic sbuf_t *
312296417Sdimallocsb(void)
313296417Sdim{
314212904Sdim	sbuf_t	*sb;
315212904Sdim
316261991Sdim	if ((sb = sbfrlst) != NULL) {
317212904Sdim		sbfrlst = sb->sb_nxt;
318212904Sdim	} else {
319212904Sdim		if ((sb = malloc(sizeof (sbuf_t))) == NULL)
320212904Sdim			nomem();
321212904Sdim	}
322296417Sdim	(void)memset(sb, 0, sizeof (*sb));
323296417Sdim	return (sb);
324212904Sdim}
325296417Sdim
326296417Sdim/*
327296417Sdim * Put a sbuf structure to the free list
328296417Sdim */
329212904Sdimstatic void
330243830Sdimfreesb(sbuf_t *sb)
331276479Sdim{
332276479Sdim
333296417Sdim	sb->sb_nxt = sbfrlst;
334296417Sdim	sbfrlst = sb;
335296417Sdim}
336296417Sdim
337296417Sdim/*
338296417Sdim * Read a character and ensure that it is positive (except EOF).
339212904Sdim * Increment line count(s) if necessary.
340276479Sdim */
341276479Sdimstatic int
342296417Sdiminpc(void)
343261991Sdim{
344212904Sdim	int	c;
345212904Sdim
346212904Sdim	if ((c = input()) != EOF && (c &= CHAR_MASK) == '\n')
347212904Sdim		incline();
348276479Sdim	return (c);
349212904Sdim}
350212904Sdim
351212904Sdimstatic int
352212904Sdimhash(const char *s)
353212904Sdim{
354212904Sdim	u_int	v;
355212904Sdim	const	u_char *us;
356212904Sdim
357212904Sdim	v = 0;
358261991Sdim	for (us = (const u_char *)s; *us != '\0'; us++) {
359276479Sdim		v = (v << sizeof (v)) + *us;
360276479Sdim		v ^= v >> (sizeof (v) * CHAR_BIT - sizeof (v));
361212904Sdim	}
362212904Sdim	return (v % HSHSIZ1);
363212904Sdim}
364218893Sdim
365223017Sdim/*
366276479Sdim * Lex has found a letter followed by zero or more letters or digits.
367223017Sdim * It looks for a symbol in the symbol table with the same name. This
368223017Sdim * symbol must either be a keyword or a symbol of the type required by
369223017Sdim * symtyp (label, member, tag, ...).
370280031Sdim *
371280031Sdim * If it is a keyword, the token is returned. In some cases it is described
372280031Sdim * more deeply by data written to yylval.
373280031Sdim *
374223017Sdim * If it is a symbol, T_NAME is returned and the pointer to a sbuf struct
375296417Sdim * is stored in yylval. This struct contains the name of the symbol, it's
376223017Sdim * length and hash value. If there is already a symbol of the same name
377223017Sdim * and type in the symbol table, the sbuf struct also contains a pointer
378223017Sdim * to the symbol table entry.
379261991Sdim */
380212904Sdimstatic int
381223017Sdimname(void)
382261991Sdim{
383212904Sdim	char	*s;
384261991Sdim	sbuf_t	*sb;
385212904Sdim	sym_t	*sym;
386261991Sdim	int	tok;
387261991Sdim
388212904Sdim	sb = allocsb();
389212904Sdim	sb->sb_name = yytext;
390296417Sdim	sb->sb_len = yyleng;
391296417Sdim	sb->sb_hash = hash(yytext);
392296417Sdim
393212904Sdim	if ((sym = search(sb)) != NULL && sym->s_keyw) {
394226633Sdim		freesb(sb);
395212904Sdim		return (keyw(sym));
396212904Sdim	}
397296417Sdim
398296417Sdim	sb->sb_sym = sym;
399261991Sdim
400288943Sdim	if (sym != NULL) {
401212904Sdim		if (blklev < sym->s_blklev)
402212904Sdim			lerror("name() 1");
403261991Sdim		sb->sb_name = sym->s_name;
404212904Sdim		sb->sb_len = strlen(sym->s_name);
405296417Sdim		tok = sym->s_scl == TYPEDEF ? T_TYPENAME : T_NAME;
406296417Sdim	} else {
407296417Sdim		s = getblk(yyleng + 1);
408288943Sdim		(void)memcpy(s, yytext, yyleng + 1);
409212904Sdim		sb->sb_name = s;
410212904Sdim		sb->sb_len = yyleng;
411261991Sdim		tok = T_NAME;
412288943Sdim	}
413296417Sdim
414261991Sdim	yylval.y_sb = sb;
415212904Sdim	return (tok);
416212904Sdim}
417261991Sdim
418296417Sdimstatic sym_t *
419296417Sdimsearch(sbuf_t *sb)
420296417Sdim{
421261991Sdim	sym_t	*sym;
422212904Sdim
423212904Sdim	for (sym = symtab[sb->sb_hash]; sym != NULL; sym = sym->s_link) {
424296417Sdim		if (strcmp(sym->s_name, sb->sb_name) == 0) {
425296417Sdim			if (sym->s_keyw || sym->s_kind == symtyp)
426296417Sdim				return (sym);
427261991Sdim		}
428212904Sdim	}
429212904Sdim
430296417Sdim	return (NULL);
431218893Sdim}
432261991Sdim
433221345Sdimstatic int
434212904Sdimkeyw(sym_t *sym)
435212904Sdim{
436212904Sdim	int	t;
437212904Sdim
438296417Sdim	if ((t = (int)sym->s_value.v_quad) == T_SCLASS) {
439296417Sdim		yylval.y_scl = sym->s_scl;
440212904Sdim	} else if (t == T_TYPE || t == T_SOU) {
441296417Sdim		yylval.y_tspec = sym->s_tspec;
442212904Sdim	} else if (t == T_QUAL) {
443212904Sdim		yylval.y_tqual = sym->s_tqual;
444212904Sdim	}
445261991Sdim	return (t);
446212904Sdim}
447212904Sdim
448296417Sdim/*
449212904Sdim * Convert a string representing an integer into internal representation.
450218893Sdim * The value is returned in yylval. icon() (and yylex()) returns T_CON.
451212904Sdim */
452261991Sdimstatic int
453212904Sdimicon(int base)
454296417Sdim{
455226633Sdim	int	l_suffix, u_suffix;
456212904Sdim	int	len;
457212904Sdim	const	char *cp;
458212904Sdim	char	c, *eptr;
459261991Sdim	tspec_t	typ;
460212904Sdim	u_long	ul = 0;
461212904Sdim	uint64_t uq = 0;
462212904Sdim	int	ansiu;
463261991Sdim	static	tspec_t contypes[2][3] = {
464212904Sdim		{ INT,  LONG,  QUAD },
465276479Sdim		{ UINT, ULONG, UQUAD }
466296417Sdim	};
467212904Sdim
468212904Sdim	cp = yytext;
469212904Sdim	len = yyleng;
470296417Sdim
471296417Sdim	/* skip 0x */
472296417Sdim	if (base == 16) {
473296417Sdim		cp += 2;
474296417Sdim		len -= 2;
475218893Sdim	}
476193323Sed
477218893Sdim	/* read suffixes */
478218893Sdim	l_suffix = u_suffix = 0;
479218893Sdim	for ( ; ; ) {
480218893Sdim		if ((c = cp[len - 1]) == 'l' || c == 'L') {
481296417Sdim			l_suffix++;
482280031Sdim		} else if (c == 'u' || c == 'U') {
483218893Sdim			u_suffix++;
484296417Sdim		} else {
485218893Sdim			break;
486212904Sdim		}
487218893Sdim		len--;
488218893Sdim	}
489218893Sdim	if (l_suffix > 2 || u_suffix > 1) {
490218893Sdim		/* malformed integer constant */
491218893Sdim		warning(251);
492218893Sdim		if (l_suffix > 2)
493218893Sdim			l_suffix = 2;
494218893Sdim		if (u_suffix > 1)
495218893Sdim			u_suffix = 1;
496218893Sdim	}
497218893Sdim	if (tflag && u_suffix != 0) {
498296417Sdim		/* suffix U is illegal in traditional C */
499218893Sdim		warning(97);
500218893Sdim	}
501218893Sdim	typ = contypes[u_suffix][l_suffix];
502218893Sdim
503218893Sdim	errno = 0;
504218893Sdim	if (l_suffix < 2) {
505218893Sdim		ul = strtoul(cp, &eptr, base);
506218893Sdim	} else {
507218893Sdim		uq = strtouq(cp, &eptr, base);
508218893Sdim	}
509218893Sdim	if (eptr != cp + len)
510218893Sdim		lerror("icon() 1");
511218893Sdim	if (errno != 0)
512218893Sdim		/* integer constant out of range */
513218893Sdim		warning(252);
514218893Sdim
515218893Sdim	/*
516296417Sdim	 * If the value is to big for the current type, we must choose
517218893Sdim	 * another type.
518288943Sdim	 */
519288943Sdim	ansiu = 0;
520218893Sdim	switch (typ) {
521218893Sdim	case INT:
522218893Sdim		if (ul <= INT_MAX) {
523218893Sdim			/* ok */
524218893Sdim		} else if (ul <= (unsigned)UINT_MAX && base != 10) {
525296417Sdim			typ = UINT;
526218893Sdim		} else if (ul <= LONG_MAX) {
527218893Sdim			typ = LONG;
528218893Sdim		} else {
529218893Sdim			typ = ULONG;
530218893Sdim		}
531193323Sed		if (typ == UINT || typ == ULONG) {
532193323Sed			if (tflag) {
533288943Sdim				typ = LONG;
534288943Sdim			} else if (!sflag) {
535276479Sdim				/*
536276479Sdim				 * Remember that the constant is unsigned
537276479Sdim				 * only in ANSI C
538276479Sdim				 */
539276479Sdim				ansiu = 1;
540276479Sdim			}
541276479Sdim		}
542276479Sdim		break;
543276479Sdim	case UINT:
544276479Sdim		if (ul > (u_int)UINT_MAX)
545276479Sdim			typ = ULONG;
546276479Sdim		break;
547276479Sdim	case LONG:
548276479Sdim		if (ul > LONG_MAX && !tflag) {
549296417Sdim			typ = ULONG;
550296417Sdim			if (!sflag)
551212904Sdim				ansiu = 1;
552212904Sdim		}
553296417Sdim		break;
554193323Sed	case QUAD:
555296417Sdim		if (uq > QUAD_MAX && !tflag) {
556212904Sdim			typ = UQUAD;
557212904Sdim			if (!sflag)
558212904Sdim				ansiu = 1;
559212904Sdim		}
560296417Sdim		break;
561212904Sdim		/* LINTED (enumeration values not handled in switch) */
562288943Sdim	case STRUCT:
563296417Sdim	case VOID:
564288943Sdim	case LDOUBLE:
565296417Sdim	case FUNC:
566296417Sdim	case ARRAY:
567212904Sdim	case PTR:
568212904Sdim	case ENUM:
569296417Sdim	case UNION:
570296417Sdim	case SIGNED:
571296417Sdim	case NOTSPEC:
572218893Sdim	case DOUBLE:
573212904Sdim	case FLOAT:
574296417Sdim	case UQUAD:
575218893Sdim	case ULONG:
576296417Sdim	case USHORT:
577218893Sdim	case SHORT:
578218893Sdim	case UCHAR:
579212904Sdim	case SCHAR:
580296417Sdim	case CHAR:
581212904Sdim	case UNSIGN:
582288943Sdim		break;
583296417Sdim	}
584288943Sdim
585218893Sdim	if (typ != QUAD && typ != UQUAD) {
586296417Sdim		if (isutyp(typ)) {
587212904Sdim			uq = ul;
588212904Sdim		} else {
589296417Sdim			uq = (int64_t)(long)ul;
590296417Sdim		}
591296417Sdim	}
592296417Sdim
593296417Sdim	uq = (uint64_t)xsign((int64_t)uq, typ, -1);
594296417Sdim
595296417Sdim	if ((yylval.y_val = calloc(1, sizeof(val_t))) == NULL)
596288943Sdim		nomem();
597276479Sdim	yylval.y_val->v_tspec = typ;
598288943Sdim	yylval.y_val->v_ansiu = ansiu;
599288943Sdim	yylval.y_val->v_quad = (int64_t)uq;
600276479Sdim
601276479Sdim	return (T_CON);
602288943Sdim}
603296417Sdim
604296417Sdim/*
605296417Sdim * Returns 1 if t is a signed type and the value is negative.
606296417Sdim *
607296417Sdim * len is the number of significant bits. If len is -1, len is set
608276479Sdim * to the width of type t.
609276479Sdim */
610276479Sdimint
611276479Sdimsign(int64_t q, tspec_t t, int len)
612276479Sdim{
613296417Sdim
614296417Sdim	if (t == PTR || isutyp(t))
615296417Sdim		return (0);
616296417Sdim	return (msb(q, t, len));
617296417Sdim}
618276479Sdim
619296417Sdimint
620296417Sdimmsb(int64_t q, tspec_t t, int len)
621296417Sdim{
622296417Sdim
623296417Sdim	if (len <= 0)
624276479Sdim		len = size(t);
625276479Sdim	return ((q & qbmasks[len - 1]) != 0);
626296417Sdim}
627296417Sdim
628296417Sdim/*
629296417Sdim * Extends the sign of q.
630296417Sdim */
631296417Sdimint64_t
632296417Sdimxsign(int64_t q, tspec_t t, int len)
633296417Sdim{
634296417Sdim
635296417Sdim	if (len <= 0)
636296417Sdim		len = size(t);
637296417Sdim
638296417Sdim	if (t == PTR || isutyp(t) || !sign(q, t, len)) {
639296417Sdim		q &= qlmasks[len];
640296417Sdim	} else {
641296417Sdim		q |= qumasks[len];
642296417Sdim	}
643280031Sdim	return (q);
644280031Sdim}
645296417Sdim
646296417Sdim/*
647280031Sdim * Convert a string representing a floating point value into its interal
648296417Sdim * representation. Type and value are returned in yylval. fcon()
649296417Sdim * (and yylex()) returns T_CON.
650296417Sdim * XXX Currently it is not possible to convert constants of type
651296417Sdim * long double which are greater than DBL_MAX.
652296417Sdim */
653296417Sdimstatic int
654296417Sdimfcon(void)
655296417Sdim{
656296417Sdim	const	char *cp;
657280031Sdim	int	len;
658280031Sdim	tspec_t typ;
659296417Sdim	char	c, *eptr;
660296417Sdim	double	d;
661296417Sdim	float	f = 0;
662296417Sdim
663296417Sdim	cp = yytext;
664296417Sdim	len = yyleng;
665288943Sdim
666296417Sdim	if ((c = cp[len - 1]) == 'f' || c == 'F') {
667288943Sdim		typ = FLOAT;
668296417Sdim		len--;
669296417Sdim	} else if (c == 'l' || c == 'L') {
670296417Sdim		typ = LDOUBLE;
671296417Sdim		len--;
672296417Sdim	} else {
673296417Sdim		typ = DOUBLE;
674296417Sdim	}
675296417Sdim
676296417Sdim	if (tflag && typ != DOUBLE) {
677296417Sdim		/* suffixes F and L are illegal in traditional C */
678296417Sdim		warning(98);
679296417Sdim	}
680296417Sdim
681296417Sdim	errno = 0;
682296417Sdim	d = strtod(cp, &eptr);
683296417Sdim	if (eptr != cp + len)
684296417Sdim		lerror("fcon() 1");
685296417Sdim	if (errno != 0)
686296417Sdim		/* floating-point constant out of range */
687296417Sdim		warning(248);
688296417Sdim
689296417Sdim	if (typ == FLOAT) {
690296417Sdim		f = (float)d;
691296417Sdim		if (!finite(f)) {
692296417Sdim			/* floating-point constant out of range */
693296417Sdim			warning(248);
694296417Sdim			f = f > 0 ? FLT_MAX : -FLT_MAX;
695296417Sdim		}
696296417Sdim	}
697296417Sdim
698296417Sdim	if ((yylval.y_val = calloc(1, sizeof (val_t))) == NULL)
699218893Sdim		nomem();
700210299Sed	yylval.y_val->v_tspec = typ;
701210299Sed	if (typ == FLOAT) {
702296417Sdim		yylval.y_val->v_ldbl = f;
703261991Sdim	} else {
704218893Sdim		yylval.y_val->v_ldbl = d;
705199989Srdivacky	}
706199989Srdivacky
707199989Srdivacky	return (T_CON);
708199989Srdivacky}
709199989Srdivacky
710212904Sdimstatic int
711199989Srdivackyoperator(int t, op_t o)
712296417Sdim{
713261991Sdim
714199989Srdivacky	yylval.y_op = o;
715199989Srdivacky	return (t);
716199989Srdivacky}
717199989Srdivacky
718199989Srdivacky/*
719199989Srdivacky * Called if lex found a leading \'.
720199989Srdivacky */
721212904Sdimstatic int
722199989Srdivackyccon(void)
723223017Sdim{
724223017Sdim	int	n, val, c;
725223017Sdim	char	cv;
726204642Srdivacky
727234353Sdim	n = 0;
728199989Srdivacky	val = 0;
729261991Sdim	while ((c = getescc('\'')) >= 0) {
730218893Sdim		val = (val << CHAR_BIT) + c;
731199989Srdivacky		n++;
732199989Srdivacky	}
733199989Srdivacky	if (c == -2) {
734296417Sdim		/* unterminated character constant */
735296417Sdim		error(253);
736296417Sdim	} else {
737199989Srdivacky		if (n > sizeof (int) || (n > 1 && (pflag || hflag))) {
738198113Srdivacky			/* too many characters in character constant */
739198090Srdivacky			error(71);
740198090Srdivacky		} else if (n > 1) {
741261991Sdim			/* multi-character character constant */
742199989Srdivacky			warning(294);
743296417Sdim		} else if (n == 0) {
744193323Sed			/* empty character constant */
745193323Sed			error(73);
746280031Sdim		}
747280031Sdim	}
748280031Sdim	if (n == 1) {
749280031Sdim		cv = (char)val;
750296417Sdim		val = cv;
751280031Sdim	}
752296417Sdim
753296417Sdim	yylval.y_val = xcalloc(1, sizeof (val_t));
754193323Sed	yylval.y_val->v_tspec = INT;
755193323Sed	yylval.y_val->v_quad = val;
756296417Sdim
757296417Sdim	return (T_CON);
758280031Sdim}
759280031Sdim
760280031Sdim/*
761280031Sdim * Called if lex found a leading L\'
762296417Sdim */
763280031Sdimstatic int
764296417Sdimwccon(void)
765296417Sdim{
766280031Sdim	static	char buf[MB_LEN_MAX + 1];
767280031Sdim	int	i, c;
768296417Sdim	wchar_t	wc;
769296417Sdim
770288943Sdim	i = 0;
771288943Sdim	while ((c = getescc('\'')) >= 0) {
772288943Sdim		if (i < MB_CUR_MAX)
773288943Sdim			buf[i] = (char)c;
774288943Sdim		i++;
775288943Sdim	}
776288943Sdim
777288943Sdim	wc = 0;
778288943Sdim
779288943Sdim	if (c == -2) {
780288943Sdim		/* unterminated character constant */
781288943Sdim		error(253);
782288943Sdim	} else if (c == 0) {
783288943Sdim		/* empty character constant */
784288943Sdim		error(73);
785288943Sdim	} else {
786288943Sdim		if (i > MB_CUR_MAX) {
787288943Sdim			i = MB_CUR_MAX;
788288943Sdim			/* too many characters in character constant */
789288943Sdim			error(71);
790288943Sdim		} else {
791288943Sdim			buf[i] = '\0';
792288943Sdim			(void)mbtowc(NULL, NULL, 0);
793288943Sdim			if (mbtowc(&wc, buf, MB_CUR_MAX) < 0)
794288943Sdim				/* invalid multibyte character */
795288943Sdim				error(291);
796288943Sdim		}
797296417Sdim	}
798296417Sdim
799296417Sdim	if ((yylval.y_val = calloc(1, sizeof (val_t))) == NULL)
800288943Sdim		nomem();
801288943Sdim	yylval.y_val->v_tspec = WCHAR;
802288943Sdim	yylval.y_val->v_quad = wc;
803288943Sdim
804288943Sdim	return (T_CON);
805288943Sdim}
806288943Sdim
807288943Sdim/*
808288943Sdim * Read a character which is part of a character constant or of a string
809288943Sdim * and handle escapes.
810288943Sdim *
811288943Sdim * The Argument is the character which delimits the character constant or
812288943Sdim * string.
813288943Sdim *
814288943Sdim * Returns -1 if the end of the character constant or string is reached,
815288943Sdim * -2 if the EOF is reached, and the character otherwise.
816288943Sdim */
817288943Sdimstatic int
818288943Sdimgetescc(int d)
819288943Sdim{
820288943Sdim	static	int pbc = -1;
821288943Sdim	int	n, c, v;
822296417Sdim
823296417Sdim	if (pbc == -1) {
824296417Sdim		c = inpc();
825288943Sdim	} else {
826296417Sdim		c = pbc;
827296417Sdim		pbc = -1;
828296417Sdim	}
829296417Sdim	if (c == d)
830296417Sdim		return (-1);
831296417Sdim	switch (c) {
832296417Sdim	case '\n':
833296417Sdim		if (tflag) {
834296417Sdim			/* newline in string or char constant */
835296417Sdim			error(254);
836296417Sdim			return (-2);
837296417Sdim		}
838296417Sdim		return (c);
839296417Sdim	case EOF:
840296417Sdim		return (-2);
841296417Sdim	case '\\':
842296417Sdim		switch (c = inpc()) {
843296417Sdim		case '"':
844296417Sdim			if (tflag && d == '\'')
845296417Sdim				/* \" inside character constant undef. ... */
846296417Sdim				warning(262);
847296417Sdim			return ('"');
848296417Sdim		case '\'':
849296417Sdim			return ('\'');
850296417Sdim		case '?':
851296417Sdim			if (tflag)
852296417Sdim				/* \? undefined in traditional C */
853296417Sdim				warning(263);
854296417Sdim			return ('?');
855296417Sdim		case '\\':
856296417Sdim			return ('\\');
857296417Sdim		case 'a':
858296417Sdim			if (tflag)
859296417Sdim				/* \a undefined in traditional C */
860296417Sdim				warning(81);
861288943Sdim			return ('\a');
862296417Sdim		case 'b':
863296417Sdim			return ('\b');
864296417Sdim		case 'f':
865288943Sdim			return ('\f');
866288943Sdim		case 'n':
867288943Sdim			return ('\n');
868288943Sdim		case 'r':
869288943Sdim			return ('\r');
870288943Sdim		case 't':
871288943Sdim			return ('\t');
872288943Sdim		case 'v':
873288943Sdim			if (tflag)
874288943Sdim				/* \v undefined in traditional C */
875288943Sdim				warning(264);
876288943Sdim			return ('\v');
877288943Sdim		case '8': case '9':
878288943Sdim			/* bad octal digit %c */
879288943Sdim			warning(77, c);
880288943Sdim			/* FALLTHROUGH */
881288943Sdim		case '0': case '1': case '2': case '3':
882288943Sdim		case '4': case '5': case '6': case '7':
883288943Sdim			n = 3;
884288943Sdim			v = 0;
885288943Sdim			do {
886288943Sdim				v = (v << 3) + (c - '0');
887288943Sdim				c = inpc();
888288943Sdim			} while (--n && isdigit(c) && (tflag || c <= '7'));
889288943Sdim			if (tflag && n > 0 && isdigit(c))
890288943Sdim				/* bad octal digit %c */
891288943Sdim				warning(77, c);
892288943Sdim			pbc = c;
893288943Sdim			if (v > UCHAR_MAX) {
894288943Sdim				/* character escape does not fit in char. */
895288943Sdim				warning(76);
896288943Sdim				v &= CHAR_MASK;
897288943Sdim			}
898296417Sdim			return (v);
899296417Sdim		case 'x':
900199989Srdivacky			if (tflag)
901296417Sdim				/* \x undefined in traditional C */
902296417Sdim				warning(82);
903296417Sdim			v = 0;
904296417Sdim			n = 0;
905296417Sdim			while ((c = inpc()) >= 0 && isxdigit(c)) {
906296417Sdim				c = isdigit(c) ?
907296417Sdim					c - '0' : toupper(c) - 'A' + 10;
908296417Sdim				v = (v << 4) + c;
909199989Srdivacky				if (n >= 0) {
910276479Sdim					if ((v & ~CHAR_MASK) != 0) {
911212904Sdim						/* overflow in hex escape */
912199989Srdivacky						warning(75);
913243830Sdim						n = -1;
914243830Sdim					} else {
915243830Sdim						n++;
916199989Srdivacky					}
917249423Sdim				}
918288943Sdim			}
919288943Sdim			pbc = c;
920288943Sdim			if (n == 0) {
921249423Sdim				/* no hex digits follow \x */
922243830Sdim				error(74);
923243830Sdim			} if (n == -1) {
924249423Sdim				v &= CHAR_MASK;
925243830Sdim			}
926296417Sdim			return (v);
927296417Sdim		case '\n':
928243830Sdim			return (getescc(d));
929243830Sdim		case EOF:
930243830Sdim			return (-2);
931243830Sdim		default:
932276479Sdim			if (isprint(c)) {
933243830Sdim				/* dubious escape \%c */
934243830Sdim				warning(79, c);
935280031Sdim			} else {
936296417Sdim				/* dubious escape \%o */
937243830Sdim				warning(80, c);
938280031Sdim			}
939296417Sdim		}
940243830Sdim	}
941243830Sdim	return (c);
942296417Sdim}
943296417Sdim
944243830Sdim/*
945243830Sdim * Called for preprocessor directives. Currently implemented are:
946243830Sdim *	# lineno
947276479Sdim *	# lineno "filename"
948276479Sdim */
949276479Sdimstatic void
950276479Sdimdirective(void)
951243830Sdim{
952243830Sdim	const	char *cp, *fn;
953276479Sdim	char	c, *eptr;
954243830Sdim	size_t	fnl;
955243830Sdim	long	ln;
956243830Sdim	static	int first = 1;
957243830Sdim
958261991Sdim	/* Go to first non-whitespace after # */
959199989Srdivacky	for (cp = yytext + 1; (c = *cp) == ' ' || c == '\t'; cp++)
960199989Srdivacky		continue;
961296417Sdim
962296417Sdim	if (!isdigit((unsigned char)c)) {
963261991Sdim	error:
964199989Srdivacky		/* undefined or invalid # directive */
965199989Srdivacky		warning(255);
966199989Srdivacky		return;
967199989Srdivacky	}
968280031Sdim	ln = strtol(--cp, &eptr, 10);
969296417Sdim	if (cp == eptr)
970261991Sdim		goto error;
971199989Srdivacky	if ((c = *(cp = eptr)) != ' ' && c != '\t' && c != '\0')
972276479Sdim		goto error;
973212904Sdim	while ((c = *cp++) == ' ' || c == '\t')
974199989Srdivacky		continue;
975280031Sdim	if (c != '\0') {
976296417Sdim		if (c != '"')
977261991Sdim			goto error;
978243830Sdim		fn = cp;
979243830Sdim		while ((c = *cp) != '"' && c != '\0')
980296417Sdim			cp++;
981199989Srdivacky		if (c != '"')
982199989Srdivacky			goto error;
983199989Srdivacky		if ((fnl = cp++ - fn) > PATH_MAX)
984288943Sdim			goto error;
985288943Sdim		while ((c = *cp++) == ' ' || c == '\t')
986288943Sdim			continue;
987288943Sdim#if 0
988296417Sdim		if (c != '\0')
989296417Sdim			warning("extra character(s) after directive");
990288943Sdim#endif
991288943Sdim
992288943Sdim		/* empty string means stdin */
993288943Sdim		if (fnl == 0) {
994288943Sdim			fn = "{standard input}";
995276479Sdim			fnl = 16;			/* strlen (fn) */
996276479Sdim		}
997276479Sdim		curr_pos.p_file = fnnalloc(fn, fnl);
998261991Sdim		/*
999199989Srdivacky		 * If this is the first directive, the name is the name
1000199989Srdivacky		 * of the C source file as specified at the command line.
1001199989Srdivacky		 * It is written to the output file.
1002212904Sdim		 */
1003261991Sdim		if (first) {
1004199989Srdivacky			csrc_pos.p_file = curr_pos.p_file;
1005199989Srdivacky			outsrc(curr_pos.p_file);
1006199989Srdivacky			first = 0;
1007199989Srdivacky		}
1008193323Sed	}
1009199989Srdivacky	curr_pos.p_line = (int)ln - 1;
1010288943Sdim	curr_pos.p_uniq = 0;
1011288943Sdim	if (curr_pos.p_file == csrc_pos.p_file) {
1012199989Srdivacky		csrc_pos.p_line = (int)ln - 1;
1013193323Sed		csrc_pos.p_uniq = 0;
1014288943Sdim	}
1015288943Sdim}
1016199989Srdivacky
1017199989Srdivacky/*
1018199989Srdivacky * Handle lint comments. Following comments are currently understood:
1019199989Srdivacky *	ARGSUSEDn
1020199989Srdivacky *	BITFIELDTYPE
1021199989Srdivacky *	CONSTCOND CONSTANTCOND CONSTANTCONDITION
1022199989Srdivacky *	FALLTHRU FALLTHROUGH
1023193323Sed *	LINTLIBRARY
1024199989Srdivacky *	LINTED NOSTRICT
1025280031Sdim *	LONGLONG
1026296417Sdim *	NOTREACHED
1027261991Sdim *	PRINTFLIKEn
1028243830Sdim *	PROTOLIB
1029243830Sdim *	SCANFLIKEn
1030296417Sdim *	VARARGSn
1031199989Srdivacky * If one of this comments is recognized, the arguments, if any, are
1032199989Srdivacky * parsed and a function which handles this comment is called.
1033193323Sed */
1034276479Sdimstatic void
1035276479Sdimcomment(void)
1036276479Sdim{
1037193323Sed	int	c, lc;
1038261991Sdim	static struct {
1039199989Srdivacky		const	char *keywd;
1040199989Srdivacky		int	arg;
1041199989Srdivacky		void	(*func)(int);
1042193323Sed	} keywtab[] = {
1043199989Srdivacky		{ "ARGSUSED",		1,	argsused	},
1044199989Srdivacky		{ "BITFIELDTYPE",	0,	bitfieldtype	},
1045199989Srdivacky		{ "CONSTCOND",		0,	constcond	},
1046198090Srdivacky		{ "CONSTANTCOND",	0,	constcond	},
1047193323Sed		{ "CONSTANTCONDITION",	0,	constcond	},
1048226633Sdim		{ "FALLTHRU",		0,	fallthru	},
1049226633Sdim		{ "FALLTHROUGH",	0,	fallthru	},
1050226633Sdim		{ "LINTLIBRARY",	0,	lintlib		},
1051226633Sdim		{ "LINTED",		0,	linted		},
1052218893Sdim		{ "LONGLONG",		0,	longlong	},
1053226633Sdim		{ "NOSTRICT",		0,	linted		},
1054288943Sdim		{ "NOTREACHED",		0,	notreach	},
1055226633Sdim		{ "PRINTFLIKE",		1,	printflike	},
1056226633Sdim		{ "PROTOLIB",		1,	protolib	},
1057226633Sdim		{ "SCANFLIKE",		1,	scanflike	},
1058226633Sdim		{ "VARARGS",		1,	varargs		},
1059226633Sdim	};
1060265925Sdim	char	keywd[32];
1061265925Sdim	char	arg[32];
1062265925Sdim	int	l, i, a;
1063265925Sdim	int	eoc;
1064265925Sdim
1065265925Sdim	eoc = 0;
1066265925Sdim
1067265925Sdim	/* Skip white spaces after the start of the comment */
1068288943Sdim	while ((c = inpc()) != EOF && isspace(c))
1069288943Sdim		continue;
1070226633Sdim
1071226633Sdim	/* Read the potential keyword to keywd */
1072226633Sdim	l = 0;
1073226633Sdim	while (c != EOF && isupper(c) && l < sizeof (keywd) - 1) {
1074226633Sdim		keywd[l++] = (char)c;
1075218893Sdim		c = inpc();
1076218893Sdim	}
1077226633Sdim	keywd[l] = '\0';
1078226633Sdim
1079296417Sdim	/* look for the keyword */
1080296417Sdim	for (i = 0; i < sizeof (keywtab) / sizeof (keywtab[0]); i++) {
1081296417Sdim		if (strcmp(keywtab[i].keywd, keywd) == 0)
1082296417Sdim			break;
1083296417Sdim	}
1084296417Sdim	if (i == sizeof (keywtab) / sizeof (keywtab[0]))
1085296417Sdim		goto skip_rest;
1086296417Sdim
1087296417Sdim	/* skip white spaces after the keyword */
1088296417Sdim	while (c != EOF && isspace(c))
1089296417Sdim		c = inpc();
1090296417Sdim
1091296417Sdim	/* read the argument, if the keyword accepts one and there is one */
1092296417Sdim	l = 0;
1093296417Sdim	if (keywtab[i].arg) {
1094296417Sdim		while (c != EOF && isdigit(c) && l < sizeof (arg) - 1) {
1095296417Sdim			arg[l++] = (char)c;
1096296417Sdim			c = inpc();
1097296417Sdim		}
1098296417Sdim	}
1099296417Sdim	arg[l] = '\0';
1100296417Sdim	a = l != 0 ? atoi(arg) : -1;
1101296417Sdim
1102296417Sdim	/* skip white spaces after the argument */
1103296417Sdim	while (c != EOF && isspace(c))
1104296417Sdim		c = inpc();
1105296417Sdim
1106296417Sdim	if (c != '*' || (c = inpc()) != '/') {
1107296417Sdim		if (keywtab[i].func != linted)
1108296417Sdim			/* extra characters in lint comment */
1109296417Sdim			warning(257);
1110296417Sdim	} else {
1111296417Sdim		/*
1112296417Sdim		 * remember that we have already found the end of the
1113226633Sdim		 * comment
1114226633Sdim		 */
1115226633Sdim		eoc = 1;
1116226633Sdim	}
1117226633Sdim
1118226633Sdim	if (keywtab[i].func != NULL)
1119288943Sdim		(*keywtab[i].func)(a);
1120288943Sdim
1121288943Sdim skip_rest:
1122198090Srdivacky	while (!eoc) {
1123296417Sdim		lc = c;
1124296417Sdim		if ((c = inpc()) == EOF) {
1125296417Sdim			/* unterminated comment */
1126296417Sdim			error(256);
1127296417Sdim			break;
1128296417Sdim		}
1129296417Sdim		if (lc == '*' && c == '/')
1130296417Sdim			eoc = 1;
1131296417Sdim	}
1132296417Sdim}
1133198090Srdivacky
1134226633Sdim/*
1135223017Sdim * Handle // style comments
1136223017Sdim */
1137223017Sdimstatic void
1138223017Sdimslashslashcomment(void)
1139223017Sdim{
1140223017Sdim	int c;
1141234353Sdim
1142223017Sdim	if (sflag < 2 && !gflag)
1143193323Sed		/* // comments only supported in C99 */
1144193323Sed		(void)gnuism(312, tflag ? "traditional" : "ANSI");
1145288943Sdim
1146223017Sdim	while ((c = inpc()) != EOF && c != '\n')
1147223017Sdim		continue;
1148223017Sdim}
1149223017Sdim
1150288943Sdim/*
1151288943Sdim * Clear flags for lint comments LINTED, LONGLONG and CONSTCOND.
1152288943Sdim * clrwflgs() is called after function definitions and global and
1153223017Sdim * local declarations and definitions. It is also called between
1154288943Sdim * the controlling expression and the body of control statements
1155223017Sdim * (if, switch, for, while).
1156223017Sdim */
1157296417Sdimvoid
1158296417Sdimclrwflgs(void)
1159296417Sdim{
1160296417Sdim
1161296417Sdim	nowarn = 0;
1162296417Sdim	quadflg = 0;
1163198892Srdivacky	ccflg = 0;
1164198892Srdivacky}
1165198892Srdivacky
1166198892Srdivacky/*
1167296417Sdim * Strings are stored in a dynamically alloceted buffer and passed
1168296417Sdim * in yylval.y_xstrg to the parser. The parser or the routines called
1169198892Srdivacky * by the parser are responsible for freeing this buffer.
1170198892Srdivacky */
1171198892Srdivackystatic int
1172296417Sdimstring(void)
1173296417Sdim{
1174223017Sdim	u_char	*s;
1175198892Srdivacky	int	c;
1176198892Srdivacky	size_t	len, max;
1177198892Srdivacky	strg_t	*strg;
1178198892Srdivacky
1179198892Srdivacky	if ((s = malloc(max = 64)) == NULL)
1180296417Sdim		nomem();
1181198892Srdivacky
1182198892Srdivacky	len = 0;
1183210299Sed	while ((c = getescc('"')) >= 0) {
1184198892Srdivacky		/* +1 to reserve space for a trailing NUL character */
1185296417Sdim		if (len + 1 == max)
1186223017Sdim			if ((s = realloc(s, max *= 2)) == NULL)
1187198892Srdivacky				nomem();
1188198892Srdivacky		s[len++] = (char)c;
1189296417Sdim	}
1190296417Sdim	s[len] = '\0';
1191296417Sdim	if (c == -2)
1192296417Sdim		/* unterminated string constant */
1193296417Sdim		error(258);
1194296417Sdim
1195265925Sdim	if ((strg = calloc(1, sizeof (strg_t))) == NULL)
1196265925Sdim		nomem();
1197265925Sdim	strg->st_tspec = CHAR;
1198265925Sdim	strg->st_len = len;
1199198892Srdivacky	strg->st_cp = s;
1200198892Srdivacky
1201198892Srdivacky	yylval.y_strg = strg;
1202198892Srdivacky	return (T_STRING);
1203198892Srdivacky}
1204288943Sdim
1205288943Sdimstatic int
1206243830Sdimwcstrg(void)
1207243830Sdim{
1208249423Sdim	char	*s;
1209249423Sdim	int	c, i, n, wi;
1210249423Sdim	size_t	len, max, wlen;
1211249423Sdim	wchar_t	*ws;
1212249423Sdim	strg_t	*strg;
1213249423Sdim
1214249423Sdim	if ((s = malloc(max = 64)) == NULL)
1215249423Sdim		nomem();
1216249423Sdim	len = 0;
1217249423Sdim	while ((c = getescc('"')) >= 0) {
1218249423Sdim		/* +1 to save space for a trailing NUL character */
1219249423Sdim		if (len + 1 >= max)
1220243830Sdim			if ((s = realloc(s, max *= 2)) == NULL)
1221249423Sdim				nomem();
1222198892Srdivacky		s[len++] = (char)c;
1223296417Sdim	}
1224296417Sdim	s[len] = '\0';
1225296417Sdim	if (c == -2)
1226223017Sdim		/* unterminated string constant */
1227223017Sdim		error(258);
1228223017Sdim
1229198892Srdivacky	/* get length of wide character string */
1230243830Sdim	(void)mblen(NULL, 0);
1231243830Sdim	for (i = 0, wlen = 0; i < len; i += n, wlen++) {
1232249423Sdim		if ((n = mblen(&s[i], MB_CUR_MAX)) == -1) {
1233243830Sdim			/* invalid multibyte character */
1234243830Sdim			error(291);
1235198892Srdivacky			break;
1236198892Srdivacky		}
1237198892Srdivacky		if (n == 0)
1238296417Sdim			n = 1;
1239296417Sdim	}
1240296417Sdim
1241288943Sdim	if ((ws = malloc((wlen + 1) * sizeof (wchar_t))) == NULL)
1242198090Srdivacky		nomem();
1243198090Srdivacky
1244198090Srdivacky	/* convert from multibyte to wide char */
1245198090Srdivacky	(void)mbtowc(NULL, NULL, 0);
1246198090Srdivacky	for (i = 0, wi = 0; i < len; i += n, wi++) {
1247198090Srdivacky		if ((n = mbtowc(&ws[wi], &s[i], MB_CUR_MAX)) == -1)
1248296417Sdim			break;
1249296417Sdim		if (n == 0)
1250296417Sdim			n = 1;
1251296417Sdim	}
1252296417Sdim	ws[wi] = 0;
1253296417Sdim	free(s);
1254296417Sdim
1255296417Sdim	if ((strg = calloc(1, sizeof (strg_t))) == NULL)
1256296417Sdim		nomem();
1257296417Sdim	strg->st_tspec = WCHAR;
1258296417Sdim	strg->st_len = wlen;
1259296417Sdim	strg->st_wcp = ws;
1260296417Sdim
1261296417Sdim	yylval.y_strg = strg;
1262280031Sdim	return (T_STRING);
1263198090Srdivacky}
1264198090Srdivacky
1265198090Srdivacky/*
1266296417Sdim * As noted above the scanner does not create new symbol table entries
1267296417Sdim * for symbols it cannot find in the symbol table. This is to avoid
1268296417Sdim * putting undeclared symbols into the symbol table if a syntax error
1269296417Sdim * occurs.
1270296417Sdim *
1271296417Sdim * getsym() is called as soon as it is probably ok to put the symbol to
1272296417Sdim * the symbol table. This does not mean that it is not possible that
1273296417Sdim * symbols are put to the symbol table which are than not completely
1274296417Sdim * declared due to syntax errors. To avoid too many problems in this
1275198090Srdivacky * case symbols get type int in getsym().
1276198090Srdivacky *
1277198090Srdivacky * XXX calls to getsym() should be delayed until decl1*() is called
1278198090Srdivacky */
1279198090Srdivackysym_t *
1280198090Srdivackygetsym(sbuf_t *sb)
1281198090Srdivacky{
1282198090Srdivacky	dinfo_t	*di;
1283198090Srdivacky	char	*s;
1284198892Srdivacky	sym_t	*sym;
1285296417Sdim
1286296417Sdim	sym = sb->sb_sym;
1287223017Sdim
1288223017Sdim	/*
1289223017Sdim	 * During member declaration it is possible that name() looked
1290198090Srdivacky	 * for symbols of type FVFT, although it should have looked for
1291198090Srdivacky	 * symbols of type FTAG. Same can happen for labels. Both cases
1292198090Srdivacky	 * are compensated here.
1293198090Srdivacky	 */
1294198090Srdivacky	if (symtyp == FMOS || symtyp == FLAB) {
1295296417Sdim		if (sym == NULL || sym->s_kind == FVFT)
1296296417Sdim			sym = search(sb);
1297296417Sdim	}
1298296417Sdim
1299296417Sdim	if (sym != NULL) {
1300207618Srdivacky		if (sym->s_kind != symtyp)
1301207618Srdivacky			lerror("storesym() 1");
1302207618Srdivacky		symtyp = FVFT;
1303207618Srdivacky		freesb(sb);
1304207618Srdivacky		return (sym);
1305198090Srdivacky	}
1306198090Srdivacky
1307198090Srdivacky	/* create a new symbol table entry */
1308198090Srdivacky
1309288943Sdim	/* labels must always be allocated at level 1 (outhermost block) */
1310288943Sdim	if (symtyp == FLAB) {
1311288943Sdim		sym = getlblk(1, sizeof (sym_t));
1312288943Sdim		s = getlblk(1, sb->sb_len + 1);
1313288943Sdim		(void)memcpy(s, sb->sb_name, sb->sb_len + 1);
1314198090Srdivacky		sym->s_name = s;
1315265925Sdim		sym->s_blklev = 1;
1316265925Sdim		di = dcs;
1317265925Sdim		while (di->d_nxt != NULL && di->d_nxt->d_nxt != NULL)
1318265925Sdim			di = di->d_nxt;
1319265925Sdim		if (di->d_ctx != AUTO)
1320265925Sdim			lerror("storesym() 2");
1321265925Sdim	} else {
1322198090Srdivacky		sym = getblk(sizeof (sym_t));
1323204642Srdivacky		sym->s_name = sb->sb_name;
1324296417Sdim		sym->s_blklev = blklev;
1325198090Srdivacky		di = dcs;
1326198090Srdivacky	}
1327296417Sdim
1328296417Sdim	UNIQUE_CURR_POS(sym->s_dpos);
1329198090Srdivacky	if ((sym->s_kind = symtyp) != FLAB)
1330199481Srdivacky		sym->s_type = gettyp(INT);
1331199481Srdivacky
1332199481Srdivacky	symtyp = FVFT;
1333199481Srdivacky
1334199481Srdivacky	if ((sym->s_link = symtab[sb->sb_hash]) != NULL)
1335199481Srdivacky		symtab[sb->sb_hash]->s_rlink = &sym->s_link;
1336199481Srdivacky	(symtab[sb->sb_hash] = sym)->s_rlink = &symtab[sb->sb_hash];
1337199481Srdivacky
1338199481Srdivacky	*di->d_ldlsym = sym;
1339198090Srdivacky	di->d_ldlsym = &sym->s_dlnxt;
1340198090Srdivacky
1341198090Srdivacky	freesb(sb);
1342198090Srdivacky	return (sym);
1343199481Srdivacky}
1344199481Srdivacky
1345199481Srdivacky/*
1346199481Srdivacky * Remove a symbol forever from the symbol table. s_blklev
1347199481Srdivacky * is set to -1 to avoid that the symbol will later be put
1348199481Srdivacky * back to the symbol table.
1349261991Sdim */
1350261991Sdimvoid
1351261991Sdimrmsym(sym_t *sym)
1352261991Sdim{
1353198090Srdivacky
1354198090Srdivacky	if ((*sym->s_rlink = sym->s_link) != NULL)
1355198090Srdivacky		sym->s_link->s_rlink = sym->s_rlink;
1356210299Sed	sym->s_blklev = -1;
1357210299Sed	sym->s_link = NULL;
1358198090Srdivacky}
1359261991Sdim
1360210299Sed/*
1361210299Sed * Remove a list of symbols declared at one level from the symbol
1362210299Sed * table.
1363210299Sed */
1364210299Sedvoid
1365210299Sedrmsyms(sym_t *syms)
1366210299Sed{
1367210299Sed	sym_t	*sym;
1368210299Sed
1369210299Sed	for (sym = syms; sym != NULL; sym = sym->s_dlnxt) {
1370210299Sed		if (sym->s_blklev != -1) {
1371210299Sed			if ((*sym->s_rlink = sym->s_link) != NULL)
1372210299Sed				sym->s_link->s_rlink = sym->s_rlink;
1373198090Srdivacky			sym->s_link = NULL;
1374210299Sed			sym->s_rlink = NULL;
1375198090Srdivacky		}
1376198090Srdivacky	}
1377296417Sdim}
1378296417Sdim
1379296417Sdim/*
1380296417Sdim * Put a symbol into the symbol table
1381296417Sdim */
1382261991Sdimvoid
1383223017Sdiminssym(int bl, sym_t *sym)
1384223017Sdim{
1385288943Sdim	int	h;
1386288943Sdim
1387223017Sdim	h = hash(sym->s_name);
1388223017Sdim	if ((sym->s_link = symtab[h]) != NULL)
1389223017Sdim		symtab[h]->s_rlink = &sym->s_link;
1390296417Sdim	(symtab[h] = sym)->s_rlink = &symtab[h];
1391223017Sdim	sym->s_blklev = bl;
1392223017Sdim	if (sym->s_link != NULL && sym->s_blklev < sym->s_link->s_blklev)
1393223017Sdim		lerror("inssym()");
1394199989Srdivacky}
1395199989Srdivacky
1396198396Srdivacky/*
1397198090Srdivacky * Called at level 0 after syntax errors
1398198090Srdivacky * Removes all symbols which are not declared at level 0 from the
1399199989Srdivacky * symbol table. Also frees all memory which is not associated with
1400280031Sdim * level 0.
1401198090Srdivacky */
1402218893Sdimvoid
1403296417Sdimcleanup(void)
1404296417Sdim{
1405296417Sdim	sym_t	*sym, *nsym;
1406296417Sdim	int	i;
1407218893Sdim
1408198090Srdivacky	for (i = 0; i < HSHSIZ1; i++) {
1409198090Srdivacky		for (sym = symtab[i]; sym != NULL; sym = nsym) {
1410198090Srdivacky			nsym = sym->s_link;
1411198090Srdivacky			if (sym->s_blklev >= 1) {
1412280031Sdim				if ((*sym->s_rlink = nsym) != NULL)
1413198090Srdivacky					nsym->s_rlink = sym->s_rlink;
1414218893Sdim			}
1415296417Sdim		}
1416296417Sdim	}
1417296417Sdim
1418218893Sdim	for (i = mblklev; i > 0; i--)
1419198090Srdivacky		freelblk(i);
1420198892Srdivacky}
1421198892Srdivacky
1422198892Srdivacky/*
1423280031Sdim * Create a new symbol with the name of an existing symbol.
1424198892Srdivacky */
1425218893Sdimsym_t *
1426296417Sdimpushdown(sym_t *sym)
1427296417Sdim{
1428296417Sdim	int	h;
1429296417Sdim	sym_t	*nsym;
1430218893Sdim
1431198892Srdivacky	h = hash(sym->s_name);
1432218893Sdim	nsym = getblk(sizeof (sym_t));
1433218893Sdim	if (sym->s_blklev > blklev)
1434218893Sdim		lerror("pushdown()");
1435296417Sdim	nsym->s_name = sym->s_name;
1436288943Sdim	UNIQUE_CURR_POS(nsym->s_dpos);
1437296417Sdim	nsym->s_kind = sym->s_kind;
1438288943Sdim	nsym->s_blklev = blklev;
1439296417Sdim
1440223017Sdim	if ((nsym->s_link = symtab[h]) != NULL)
1441218893Sdim		symtab[h]->s_rlink = &nsym->s_link;
1442296417Sdim	(symtab[h] = nsym)->s_rlink = &symtab[h];
1443296417Sdim
1444296417Sdim	*dcs->d_ldlsym = nsym;
1445296417Sdim	dcs->d_ldlsym = &nsym->s_dlnxt;
1446223017Sdim
1447198090Srdivacky	return (nsym);
1448265925Sdim}
1449296417Sdim
1450296417Sdim/*
1451296417Sdim * Free any dynamically allocated memory referenced by
1452296417Sdim * the value stack or yylval.
1453296417Sdim * The type of information in yylval is described by tok.
1454296417Sdim */
1455296417Sdimvoid
1456296417Sdimfreeyyv(void *sp, int tok)
1457296417Sdim{
1458265925Sdim	if (tok == T_NAME || tok == T_TYPENAME) {
1459265925Sdim		sbuf_t *sb = *(sbuf_t **)sp;
1460265925Sdim		freesb(sb);
1461265925Sdim	} else if (tok == T_CON) {
1462265925Sdim		val_t *val = *(val_t **)sp;
1463265925Sdim		free(val);
1464265925Sdim	} else if (tok == T_STRING) {
1465288943Sdim		strg_t *strg = *(strg_t **)sp;
1466288943Sdim		if (strg->st_tspec == CHAR) {
1467288943Sdim			free(strg->st_cp);
1468265925Sdim		} else if (strg->st_tspec == WCHAR) {
1469265925Sdim			free(strg->st_wcp);
1470265925Sdim		} else {
1471265925Sdim			lerror("fryylv() 1");
1472265925Sdim		}
1473265925Sdim		free(strg);
1474280031Sdim	}
1475296417Sdim}
1476265925Sdim