db_lex.c revision 92756
1/*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19 *  School of Computer Science
20 *  Carnegie Mellon University
21 *  Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie the
24 * rights to redistribute these changes.
25 *
26 * $FreeBSD: head/sys/ddb/db_lex.c 92756 2002-03-20 05:14:42Z alfred $
27 */
28
29/*
30 *	Author: David B. Golub, Carnegie Mellon University
31 *	Date:	7/90
32 */
33/*
34 * Lexical analyzer.
35 */
36#include <sys/param.h>
37
38#include <ddb/ddb.h>
39#include <ddb/db_lex.h>
40
41static char	db_line[120];
42static char *	db_lp, *db_endlp;
43
44static int	db_lex(void);
45static void 	db_flush_line(void);
46static int 	db_read_char(void);
47static void 	db_unread_char(int);
48
49int
50db_read_line()
51{
52	int	i;
53
54	i = db_readline(db_line, sizeof(db_line));
55	if (i == 0)
56	    return (0);	/* EOI */
57	db_lp = db_line;
58	db_endlp = db_lp + i;
59	return (i);
60}
61
62static void
63db_flush_line()
64{
65	db_lp = db_line;
66	db_endlp = db_line;
67}
68
69static int	db_look_char = 0;
70
71static int
72db_read_char()
73{
74	int	c;
75
76	if (db_look_char != 0) {
77	    c = db_look_char;
78	    db_look_char = 0;
79	}
80	else if (db_lp >= db_endlp)
81	    c = -1;
82	else
83	    c = *db_lp++;
84	return (c);
85}
86
87static void
88db_unread_char(c)
89	int c;
90{
91	db_look_char = c;
92}
93
94static int	db_look_token = 0;
95
96void
97db_unread_token(t)
98	int	t;
99{
100	db_look_token = t;
101}
102
103int
104db_read_token()
105{
106	int	t;
107
108	if (db_look_token) {
109	    t = db_look_token;
110	    db_look_token = 0;
111	}
112	else
113	    t = db_lex();
114	return (t);
115}
116
117db_expr_t	db_tok_number;
118char	db_tok_string[TOK_STRING_SIZE];
119
120db_expr_t	db_radix = 16;
121
122void
123db_flush_lex()
124{
125	db_flush_line();
126	db_look_char = 0;
127	db_look_token = 0;
128}
129
130static int
131db_lex()
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		db_flush_lex();
185		return (tEOF);
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	    }
203	    *cp++ = c;
204	    while (1) {
205		c = db_read_char();
206		if ((c >= 'A' && c <= 'Z') ||
207		    (c >= 'a' && c <= 'z') ||
208		    (c >= '0' && c <= '9') ||
209		    c == '_' || c == '\\' || c == ':' || c == '.')
210		{
211		    if (c == '\\') {
212			c = db_read_char();
213			if (c == '\n' || c == -1)
214			    db_error("Bad escape\n");
215		    }
216		    *cp++ = c;
217		    if (cp == db_tok_string+sizeof(db_tok_string)) {
218			db_error("String too long\n");
219			db_flush_lex();
220			return (tEOF);
221		    }
222		    continue;
223		}
224		else {
225		    *cp = '\0';
226		    break;
227		}
228	    }
229	    db_unread_char(c);
230	    return (tIDENT);
231	}
232
233	switch (c) {
234	    case '+':
235		return (tPLUS);
236	    case '-':
237		return (tMINUS);
238	    case '.':
239		c = db_read_char();
240		if (c == '.')
241		    return (tDOTDOT);
242		db_unread_char(c);
243		return (tDOT);
244	    case '*':
245		return (tSTAR);
246	    case '/':
247		return (tSLASH);
248	    case '=':
249		return (tEQ);
250	    case '%':
251		return (tPCT);
252	    case '#':
253		return (tHASH);
254	    case '(':
255		return (tLPAREN);
256	    case ')':
257		return (tRPAREN);
258	    case ',':
259		return (tCOMMA);
260	    case '"':
261		return (tDITTO);
262	    case '$':
263		return (tDOLLAR);
264	    case '!':
265		return (tEXCL);
266	    case '<':
267		c = db_read_char();
268		if (c == '<')
269		    return (tSHIFT_L);
270		db_unread_char(c);
271		break;
272	    case '>':
273		c = db_read_char();
274		if (c == '>')
275		    return (tSHIFT_R);
276		db_unread_char(c);
277		break;
278	    case -1:
279		return (tEOF);
280	}
281	db_printf("Bad character\n");
282	db_flush_lex();
283	return (tEOF);
284}
285