1 /*	$OpenBSD: db_lex.c,v 1.8 2002/07/01 21:56:55 miod Exp $	*/
2 /*	$NetBSD: db_lex.c,v 1.8 1996/02/05 01:57:05 christos Exp $	*/
3 
4 /*
5  * Mach Operating System
6  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
7  * All Rights Reserved.
8  *
9  * Permission to use, copy, modify and distribute this software and its
10  * documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  *
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  *
19  * Carnegie Mellon requests users of this software to return to
20  *
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  *
26  * any improvements or extensions that they make and grant Carnegie Mellon
27  * the rights to redistribute these changes.
28  *
29  *	Author: David B. Golub, Carnegie Mellon University
30  *	Date:	7/90
31  */
32 
33 /*
34  * Lexical analyzer.
35  */
36 #include <sys/param.h>
37 #include <sys/proc.h>
38 
39 #include <uvm/uvm_extern.h>
40 
41 #include <machine/db_machdep.h>
42 
43 #include <ddb/db_lex.h>
44 #include <ddb/db_output.h>
45 #include <ddb/db_command.h>
46 #include <ddb/db_sym.h>
47 #include <ddb/db_extern.h>
48 #include <ddb/db_var.h>
49 
50 char	db_line[120];
51 char *	db_lp, *db_endlp;
52 
53 db_expr_t db_tok_number;
54 char	db_tok_string[TOK_STRING_SIZE];
55 
56 int
db_read_line()57 db_read_line()
58 {
59 	int	i;
60 
61 	i = db_readline(db_line, sizeof(db_line));
62 	if (i == 0)
63 	    return (0);	/* EOI */
64 	db_lp = db_line;
65 	db_endlp = db_lp + i;
66 	return (i);
67 }
68 
69 void
db_flush_line()70 db_flush_line()
71 {
72 	db_lp = db_line;
73 	db_endlp = db_line;
74 }
75 
76 int	db_look_char = 0;
77 
78 int
db_read_char()79 db_read_char()
80 {
81 	int	c;
82 
83 	if (db_look_char != 0) {
84 	    c = db_look_char;
85 	    db_look_char = 0;
86 	}
87 	else if (db_lp >= db_endlp)
88 	    c = -1;
89 	else
90 	    c = *db_lp++;
91 	return (c);
92 }
93 
94 void
db_unread_char(c)95 db_unread_char(c)
96 	int c;
97 {
98 	db_look_char = c;
99 }
100 
101 int	db_look_token = 0;
102 
103 void
db_unread_token(t)104 db_unread_token(t)
105 	int	t;
106 {
107 	db_look_token = t;
108 }
109 
110 int
db_read_token()111 db_read_token()
112 {
113 	int	t;
114 
115 	if (db_look_token) {
116 	    t = db_look_token;
117 	    db_look_token = 0;
118 	}
119 	else
120 	    t = db_lex();
121 	return (t);
122 }
123 
124 void
db_flush_lex()125 db_flush_lex()
126 {
127 	db_flush_line();
128 	db_look_char = 0;
129 	db_look_token = 0;
130 }
131 
132 int
db_lex()133 db_lex()
134 {
135 	int	c;
136 
137 	c = db_read_char();
138 	while (c <= ' ' || c > '~') {
139 	    if (c == '\n' || c == -1)
140 		return (tEOL);
141 	    c = db_read_char();
142 	}
143 
144 	if (c >= '0' && c <= '9') {
145 	    /* number */
146 	    int	r, digit = 0;
147 
148 	    if (c > '0')
149 		r = db_radix;
150 	    else {
151 		c = db_read_char();
152 		if (c == 'O' || c == 'o')
153 		    r = 8;
154 		else if (c == 'T' || c == 't')
155 		    r = 10;
156 		else if (c == 'X' || c == 'x')
157 		    r = 16;
158 		else {
159 		    r = db_radix;
160 		    db_unread_char(c);
161 		}
162 		c = db_read_char();
163 	    }
164 	    db_tok_number = 0;
165 	    for (;;) {
166 		if (c >= '0' && c <= ((r == 8) ? '7' : '9'))
167 		    digit = c - '0';
168 		else if (r == 16 && ((c >= 'A' && c <= 'F') ||
169 				     (c >= 'a' && c <= 'f'))) {
170 		    if (c >= 'a')
171 			digit = c - 'a' + 10;
172 		    else if (c >= 'A')
173 			digit = c - 'A' + 10;
174 		}
175 		else
176 		    break;
177 		db_tok_number = db_tok_number * r + digit;
178 		c = db_read_char();
179 	    }
180 	    if ((c >= '0' && c <= '9') ||
181 		(c >= 'A' && c <= 'Z') ||
182 		(c >= 'a' && c <= 'z') ||
183 		(c == '_'))
184 	    {
185 		db_error("Bad character in number\n");
186 		/*NOTREACHED*/
187 	    }
188 	    db_unread_char(c);
189 	    return (tNUMBER);
190 	}
191 	if ((c >= 'A' && c <= 'Z') ||
192 	    (c >= 'a' && c <= 'z') ||
193 	    c == '_' || c == '\\')
194 	{
195 	    /* string */
196 	    char *cp;
197 
198 	    cp = db_tok_string;
199 	    if (c == '\\') {
200 		c = db_read_char();
201 		if (c == '\n' || c == -1) {
202 		    db_error("Bad escape\n");
203 		    /*NOTREACHED*/
204 		}
205 	    }
206 	    *cp++ = c;
207 	    while (1) {
208 		c = db_read_char();
209 		if ((c >= 'A' && c <= 'Z') ||
210 		    (c >= 'a' && c <= 'z') ||
211 		    (c >= '0' && c <= '9') ||
212 		    c == '_' || c == '\\' || c == ':')
213 		{
214 		    if (c == '\\') {
215 			c = db_read_char();
216 			if (c == '\n' || c == -1) {
217 			    db_error("Bad escape\n");
218 			    /*NOTREACHED*/
219 			}
220 		    }
221 		    *cp++ = c;
222 		    if (cp == db_tok_string+sizeof(db_tok_string)) {
223 			db_error("String too long\n");
224 			/*NOTREACHED*/
225 		    }
226 		    continue;
227 		}
228 		else {
229 		    *cp = '\0';
230 		    break;
231 		}
232 	    }
233 	    db_unread_char(c);
234 	    return (tIDENT);
235 	}
236 
237 	switch (c) {
238 	    case '+':
239 		return (tPLUS);
240 	    case '-':
241 		return (tMINUS);
242 	    case '.':
243 		c = db_read_char();
244 		if (c == '.')
245 		    return (tDOTDOT);
246 		db_unread_char(c);
247 		return (tDOT);
248 	    case '*':
249 		return (tSTAR);
250 	    case '/':
251 		return (tSLASH);
252 	    case '=':
253 		return (tEQ);
254 	    case '%':
255 		return (tPCT);
256 	    case '#':
257 		return (tHASH);
258 	    case '(':
259 		return (tLPAREN);
260 	    case ')':
261 		return (tRPAREN);
262 	    case ',':
263 		return (tCOMMA);
264 	    case '"':
265 		return (tDITTO);
266 	    case '$':
267 		return (tDOLLAR);
268 	    case '!':
269 		return (tEXCL);
270 	    case '<':
271 		c = db_read_char();
272 		if (c == '<')
273 		    return (tSHIFT_L);
274 		db_unread_char(c);
275 		break;
276 	    case '>':
277 		c = db_read_char();
278 		if (c == '>')
279 		    return (tSHIFT_R);
280 		db_unread_char(c);
281 		break;
282 	    case -1:
283 		return (tEOF);
284 	}
285 	db_printf("Bad character\n");
286 	db_flush_lex();
287 	return (tEOF);
288 }
289