xref: /openbsd/sys/ddb/db_lex.c (revision 17df1aa7)
1 /*	$OpenBSD: db_lex.c,v 1.9 2006/03/13 06:23:20 jsg 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
57 db_read_line(void)
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
70 db_flush_line(void)
71 {
72 	db_lp = db_line;
73 	db_endlp = db_line;
74 }
75 
76 int	db_look_char = 0;
77 
78 int
79 db_read_char(void)
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
95 db_unread_char(int c)
96 {
97 	db_look_char = c;
98 }
99 
100 int	db_look_token = 0;
101 
102 void
103 db_unread_token(int t)
104 {
105 	db_look_token = t;
106 }
107 
108 int
109 db_read_token(void)
110 {
111 	int	t;
112 
113 	if (db_look_token) {
114 	    t = db_look_token;
115 	    db_look_token = 0;
116 	}
117 	else
118 	    t = db_lex();
119 	return (t);
120 }
121 
122 void
123 db_flush_lex(void)
124 {
125 	db_flush_line();
126 	db_look_char = 0;
127 	db_look_token = 0;
128 }
129 
130 int
131 db_lex(void)
132 {
133 	int	c;
134 
135 	c = db_read_char();
136 	while (c <= ' ' || c > '~') {
137 	    if (c == '\n' || c == -1)
138 		return (tEOL);
139 	    c = db_read_char();
140 	}
141 
142 	if (c >= '0' && c <= '9') {
143 	    /* number */
144 	    int	r, digit = 0;
145 
146 	    if (c > '0')
147 		r = db_radix;
148 	    else {
149 		c = db_read_char();
150 		if (c == 'O' || c == 'o')
151 		    r = 8;
152 		else if (c == 'T' || c == 't')
153 		    r = 10;
154 		else if (c == 'X' || c == 'x')
155 		    r = 16;
156 		else {
157 		    r = db_radix;
158 		    db_unread_char(c);
159 		}
160 		c = db_read_char();
161 	    }
162 	    db_tok_number = 0;
163 	    for (;;) {
164 		if (c >= '0' && c <= ((r == 8) ? '7' : '9'))
165 		    digit = c - '0';
166 		else if (r == 16 && ((c >= 'A' && c <= 'F') ||
167 				     (c >= 'a' && c <= 'f'))) {
168 		    if (c >= 'a')
169 			digit = c - 'a' + 10;
170 		    else if (c >= 'A')
171 			digit = c - 'A' + 10;
172 		}
173 		else
174 		    break;
175 		db_tok_number = db_tok_number * r + digit;
176 		c = db_read_char();
177 	    }
178 	    if ((c >= '0' && c <= '9') ||
179 		(c >= 'A' && c <= 'Z') ||
180 		(c >= 'a' && c <= 'z') ||
181 		(c == '_'))
182 	    {
183 		db_error("Bad character in number\n");
184 		/*NOTREACHED*/
185 	    }
186 	    db_unread_char(c);
187 	    return (tNUMBER);
188 	}
189 	if ((c >= 'A' && c <= 'Z') ||
190 	    (c >= 'a' && c <= 'z') ||
191 	    c == '_' || c == '\\')
192 	{
193 	    /* string */
194 	    char *cp;
195 
196 	    cp = db_tok_string;
197 	    if (c == '\\') {
198 		c = db_read_char();
199 		if (c == '\n' || c == -1) {
200 		    db_error("Bad escape\n");
201 		    /*NOTREACHED*/
202 		}
203 	    }
204 	    *cp++ = c;
205 	    while (1) {
206 		c = db_read_char();
207 		if ((c >= 'A' && c <= 'Z') ||
208 		    (c >= 'a' && c <= 'z') ||
209 		    (c >= '0' && c <= '9') ||
210 		    c == '_' || c == '\\' || c == ':')
211 		{
212 		    if (c == '\\') {
213 			c = db_read_char();
214 			if (c == '\n' || c == -1) {
215 			    db_error("Bad escape\n");
216 			    /*NOTREACHED*/
217 			}
218 		    }
219 		    *cp++ = c;
220 		    if (cp == db_tok_string+sizeof(db_tok_string)) {
221 			db_error("String too long\n");
222 			/*NOTREACHED*/
223 		    }
224 		    continue;
225 		}
226 		else {
227 		    *cp = '\0';
228 		    break;
229 		}
230 	    }
231 	    db_unread_char(c);
232 	    return (tIDENT);
233 	}
234 
235 	switch (c) {
236 	    case '+':
237 		return (tPLUS);
238 	    case '-':
239 		return (tMINUS);
240 	    case '.':
241 		c = db_read_char();
242 		if (c == '.')
243 		    return (tDOTDOT);
244 		db_unread_char(c);
245 		return (tDOT);
246 	    case '*':
247 		return (tSTAR);
248 	    case '/':
249 		return (tSLASH);
250 	    case '=':
251 		return (tEQ);
252 	    case '%':
253 		return (tPCT);
254 	    case '#':
255 		return (tHASH);
256 	    case '(':
257 		return (tLPAREN);
258 	    case ')':
259 		return (tRPAREN);
260 	    case ',':
261 		return (tCOMMA);
262 	    case '"':
263 		return (tDITTO);
264 	    case '$':
265 		return (tDOLLAR);
266 	    case '!':
267 		return (tEXCL);
268 	    case '<':
269 		c = db_read_char();
270 		if (c == '<')
271 		    return (tSHIFT_L);
272 		db_unread_char(c);
273 		break;
274 	    case '>':
275 		c = db_read_char();
276 		if (c == '>')
277 		    return (tSHIFT_R);
278 		db_unread_char(c);
279 		break;
280 	    case -1:
281 		return (tEOF);
282 	}
283 	db_printf("Bad character\n");
284 	db_flush_lex();
285 	return (tEOF);
286 }
287