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