xref: /original-bsd/old/as.vax/asscan4.c (revision a9c19d04)
1 /*
2  * Copyright (c) 1982 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)asscan4.c	5.1 (Berkeley) 04/30/85";
9 #endif not lint
10 
11 #include "asscanl.h"
12 
13 #define	reg	register
14 #define	NUMSIZE	128	/* how many characters long a number can be */
15 #define	FLTCHAR(x)	(INCHARSET((x),(DIGIT|SIGN|FLOATEXP|POINT)))
16 
17 static char	numbuf[NUMSIZE];
18 
19 #define	BACK(backval)	intval = backval; goto stuffback;
20 
21 int number(ch)
22 	reg	int	ch;
23 {
24 		int	radix;
25 		int	digit;		/* part of number being constructed */
26 	reg	int	intval;		/* number being constructed */
27 	reg	char	*cp;
28 	reg	char	*inbufptr;
29 	reg	int	inbufcnt;
30 		char	ch1;
31 		Bignum	floatnumber();
32 		Ovf	overflow;	/* overflow flag */
33 		int	maxstrlg;
34 
35 	MEMTOREGBUF;
36 	cp = numbuf;
37 	radix = 10;
38 
39 	switch(ch){
40 	case '0':
41 		switch(ch = getchar()){
42 		case 'b':
43 			yylval = -1;
44 			BACK(BFINT);
45 		case 'f':
46 			/*
47 			 * Check if it is a local label by peeking ahead
48 			 */
49 			ch1 = getchar();
50 			ungetc(ch1);
51 			if (!FLTCHAR(ch1)){
52 				yylval = 1;
53 				BACK(BFINT);
54 			}
55 			/*FALLTHROUGH*/
56 		case 'F': ch = 'f';	goto floatnum;
57 		case 'd':
58 		case 'D': ch = 'd';	goto floatnum;
59 		case 'h':
60 		case 'H': ch = 'h';	goto floatnum;
61 		case 'g':
62 		case 'G': ch = 'g';	goto floatnum;
63 
64 		case 'x':
65 		case 'X':
66 			ch = '0';
67 			radix = 16;
68 			break;
69 		case '0':
70 		case '1': case '2': case '3': case '4':
71 		case '5': case '6': case '7': case '8':
72 		case '9':
73 			radix = 8;
74 			break;
75 		default:	/* single 0 */
76 			ungetc(ch);
77 			intval = 0;
78 			goto smallnum;
79 		}
80 		break;
81 
82 	case '1': case '2': case '3': case '4':
83 	case '5': case '6': case '7': case '8':
84 	case '9':
85 		switch(ch1 = getchar()){
86 		case 'f':
87 			yylval = ((ch - '0') + 1);
88 			BACK(BFINT);
89 		case 'b':
90 			yylval = -((ch - '0') + 1);
91 			BACK(BFINT);
92 		default:
93 			ungetc(ch1);	/* put back non zero */
94 		}
95 		radix = 10;
96 		break;
97 	}
98 	intval = 0;
99 	/*
100 	 *	There is a character in ch that must be used to
101 	 *	cons up the number; we can't ungetc it
102 	 */
103 	do{
104 		digit = ch - '0';
105 		switch(radix){
106 		case 8:
107 			intval <<= 3;
108 			break;
109 		case 10:
110 			intval *= 10;
111 			break;
112 		case 16:
113 			intval <<= 4;
114 			if (INCHARSET(ch, HEXLDIGIT)){
115 				digit = (ch - 'a') + 10;
116 				break;
117 			}
118 			if (INCHARSET(ch, HEXUDIGIT)){
119 				digit = (ch - 'A') + 10;
120 				break;
121 			}
122 		}
123 		*cp++ = ch;
124 		/*
125 		 *	Build a negative number, then negate it
126 		 */
127 		intval -= digit;
128 
129 		ch = getchar();
130 		if(!INCHARSET(ch, DIGIT)){
131 			if (radix != 16)
132 				break;
133 			if(!INCHARSET(ch, (HEXLDIGIT|HEXUDIGIT)))
134 				break;
135 		}
136 	} while (1);
137 	ungetc(ch);
138 	*cp = 0;
139 	maxstrlg = cp - numbuf;
140 	/*
141 	 *	See if the number is too large for our previous calculation
142 	 */
143 	switch(radix){
144 	case 16:
145 		if (maxstrlg > 8)
146 			goto bignum;
147 		break;
148 	case 10:
149 		if (maxstrlg >= 10)
150 			goto bignum;
151 		break;
152 	case 8:
153 		if (maxstrlg > 11)
154 			goto bignum;
155 		if (maxstrlg == 11 && numbuf[0] > 3)
156 			goto bignum;
157 		break;
158 	}
159 	/*
160 	 *	Negate the number
161 	 */
162   smallnum: ;
163 	yylval = -intval;
164 	BACK(INT);
165   bignum: ;
166 	yybignum = as_atoi(numbuf, radix, &overflow);
167 	BACK(BIGNUM);
168   floatnum: ;
169 	REGTOMEMBUF;
170 	yybignum = floatnumber(ch);
171 	return(BIGNUM);
172  stuffback: ;
173 	REGTOMEMBUF;
174 	return(intval);
175 }
176 
177 #define	TOOLONG \
178 	if (cp == &numbuf[NUMSIZE]){ \
179 		if (passno == 2) \
180 			yywarning(toolong); \
181 			goto process; \
182 	}
183 #define	scanit(sign) \
184 	REGTOMEMBUF; \
185 	error |= scanint(sign, &cp); \
186 	MEMTOREGBUF; \
187 	ch = getchar(); \
188 	TOOLONG;
189 
190 Bignum floatnumber(fltradix)
191 	int	fltradix;
192 {
193 		char	*cp;
194 		int	ch;
195 		char	*toolong = "Floating number too long.";
196 		char	*prologue =
197 			"Floating 0%c conflicts with exponent %c; choose %c";
198 		/*
199 		 *	This is not implemented yet:
200 		 *	overflow is set on floating overflow.
201 		 */
202 		Ovf	overflow;
203 		int	error;
204 		int	fractOK;
205 	reg	char	*inbufptr;
206 	reg	int	inbufcnt;
207 
208 	MEMTOREGBUF;
209 	cp = numbuf;
210 	error = 0;
211 	fractOK = 0;
212 
213 	scanit(1);
214 	if(INCHARSET(ch, POINT)){
215 		fractOK++;
216 		*cp++ = '.';
217 		scanit(0);
218 	}
219 	if(INCHARSET(ch, FLOATEXP)){
220 		fractOK++;
221 		if(ch != fltradix){
222 			if (passno == 2)
223 				yywarning(prologue, fltradix, ch, fltradix);
224 		}
225 		switch(fltradix){
226 		case 'd':
227 		case 'f':
228 			*cp++ = 'e';		/* will be read by atof() */
229 			break;
230 		default:
231 			*cp++ = fltradix;	/* will be read by bigatof() */
232 			break;
233 		}
234 		scanit(1);
235 	}
236 	if (error || fractOK == 0){
237 		yyerror("Badly formatted floating point number.");
238 	}
239 	ungetc(ch);
240 	*cp++ = 0;
241 
242   process: ;
243 	switch(fltradix){
244 	case 'f':	fltradix = TYPF;	break;
245 	case 'd':	fltradix = TYPD;	break;
246 	case 'g':	fltradix = TYPG;	nGHnumbers++; break;
247 	case 'h':	fltradix = TYPH;	nGHnumbers++; break;
248 	}
249 	REGTOMEMBUF;
250 	/*
251 	 *	The overflow value is lost in the call to as_atof
252 	 */
253 	return(as_atof(numbuf, fltradix, &overflow));
254 }
255 /*
256  *	Scan an optionally signed integer, putting back the lookahead
257  *	character when finished scanning.
258  */
259 int scanint(signOK, dstcpp)
260 	int	signOK;
261 	char	**dstcpp;
262 {
263 		int	ch;
264 		int	back = 0;
265 	reg	char	*inbufptr;
266 	reg	int	inbufcnt;
267 
268 	MEMTOREGBUF;
269 	ch = getchar();
270 	while (INCHARSET(ch, SIGN)){
271 		if (signOK && !back)
272 			*((*dstcpp)++) = ch;
273 		else
274 			back = 1;
275 		ch = getchar();
276 	}
277 	while (INCHARSET(ch, DIGIT)){
278 		*((*dstcpp)++) = ch;
279 		ch = getchar();
280 	}
281 	ungetc(ch);
282 	REGTOMEMBUF;
283 	return(back);
284 }
285