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