- Port rtw(4) from NetBSD, which supports various RealTek 8180 chip based
[dragonfly.git] / sys / ddb / db_lex.c
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: src/sys/ddb/db_lex.c,v 1.18 1999/08/28 00:41:08 peter Exp $
27  * $DragonFly: src/sys/ddb/db_lex.c,v 1.5 2005/12/23 21:35:44 swildner Exp $
28  */
29
30 /*
31  *      Author: David B. Golub, Carnegie Mellon University
32  *      Date:   7/90
33  */
34 /*
35  * Lexical analyzer.
36  */
37 #include <sys/param.h>
38
39 #include <ddb/ddb.h>
40 #include <ddb/db_lex.h>
41
42 static char     db_line[120];
43 static char *   db_lp, *db_endlp;
44
45 static int      db_lex (void);
46 static void     db_flush_line (void);
47 static int      db_read_char (void);
48 static void     db_unread_char (int);
49
50 int
51 db_read_line(void)
52 {
53         int     i;
54
55         i = db_readline(db_line, sizeof(db_line));
56         if (i == 0)
57             return (0); /* EOI */
58         db_lp = db_line;
59         db_endlp = db_lp + i;
60         return (i);
61 }
62
63 static void
64 db_flush_line(void)
65 {
66         db_lp = db_line;
67         db_endlp = db_line;
68 }
69
70 static int      db_look_char = 0;
71
72 static int
73 db_read_char(void)
74 {
75         int     c;
76
77         if (db_look_char != 0) {
78             c = db_look_char;
79             db_look_char = 0;
80         }
81         else if (db_lp >= db_endlp)
82             c = -1;
83         else
84             c = *db_lp++;
85         return (c);
86 }
87
88 static void
89 db_unread_char(int c)
90 {
91         db_look_char = c;
92 }
93
94 static int      db_look_token = 0;
95
96 void
97 db_unread_token(int t)
98 {
99         db_look_token = t;
100 }
101
102 int
103 db_read_token(void)
104 {
105         int     t;
106
107         if (db_look_token) {
108             t = db_look_token;
109             db_look_token = 0;
110         }
111         else
112             t = db_lex();
113         return (t);
114 }
115
116 db_expr_t       db_tok_number;
117 char    db_tok_string[TOK_STRING_SIZE];
118
119 db_expr_t       db_radix = 16;
120
121 void
122 db_flush_lex(void)
123 {
124         db_flush_line();
125         db_look_char = 0;
126         db_look_token = 0;
127 }
128
129 static int
130 db_lex(void)
131 {
132         int     c;
133
134         c = db_read_char();
135         while (c <= ' ' || c > '~') {
136             if (c == '\n' || c == -1)
137                 return (tEOL);
138             c = db_read_char();
139         }
140
141         if (c >= '0' && c <= '9') {
142             /* number */
143             int r, digit = 0;
144
145             if (c > '0')
146                 r = db_radix;
147             else {
148                 c = db_read_char();
149                 if (c == 'O' || c == 'o')
150                     r = 8;
151                 else if (c == 'T' || c == 't')
152                     r = 10;
153                 else if (c == 'X' || c == 'x')
154                     r = 16;
155                 else {
156                     r = db_radix;
157                     db_unread_char(c);
158                 }
159                 c = db_read_char();
160             }
161             db_tok_number = 0;
162             for (;;) {
163                 if (c >= '0' && c <= ((r == 8) ? '7' : '9'))
164                     digit = c - '0';
165                 else if (r == 16 && ((c >= 'A' && c <= 'F') ||
166                                      (c >= 'a' && c <= 'f'))) {
167                     if (c >= 'a')
168                         digit = c - 'a' + 10;
169                     else if (c >= 'A')
170                         digit = c - 'A' + 10;
171                 }
172                 else
173                     break;
174                 db_tok_number = db_tok_number * r + digit;
175                 c = db_read_char();
176             }
177             if ((c >= '0' && c <= '9') ||
178                 (c >= 'A' && c <= 'Z') ||
179                 (c >= 'a' && c <= 'z') ||
180                 (c == '_'))
181             {
182                 db_error("Bad character in number\n");
183                 db_flush_lex();
184                 return (tEOF);
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             }
202             *cp++ = c;
203             while (1) {
204                 c = db_read_char();
205                 if ((c >= 'A' && c <= 'Z') ||
206                     (c >= 'a' && c <= 'z') ||
207                     (c >= '0' && c <= '9') ||
208                     c == '_' || c == '\\' || c == ':')
209                 {
210                     if (c == '\\') {
211                         c = db_read_char();
212                         if (c == '\n' || c == -1)
213                             db_error("Bad escape\n");
214                     }
215                     *cp++ = c;
216                     if (cp == db_tok_string+sizeof(db_tok_string)) {
217                         db_error("String too long\n");
218                         db_flush_lex();
219                         return (tEOF);
220                     }
221                     continue;
222                 }
223                 else {
224                     *cp = '\0';
225                     break;
226                 }
227             }
228             db_unread_char(c);
229             return (tIDENT);
230         }
231
232         switch (c) {
233             case '+':
234                 return (tPLUS);
235             case '-':
236                 return (tMINUS);
237             case '.':
238                 c = db_read_char();
239                 if (c == '.')
240                     return (tDOTDOT);
241                 db_unread_char(c);
242                 return (tDOT);
243             case '*':
244                 return (tSTAR);
245             case '/':
246                 return (tSLASH);
247             case '=':
248                 return (tEQ);
249             case '%':
250                 return (tPCT);
251             case '#':
252                 return (tHASH);
253             case '(':
254                 return (tLPAREN);
255             case ')':
256                 return (tRPAREN);
257             case ',':
258                 return (tCOMMA);
259             case '"':
260                 return (tDITTO);
261             case '$':
262                 return (tDOLLAR);
263             case '!':
264                 return (tEXCL);
265             case '<':
266                 c = db_read_char();
267                 if (c == '<')
268                     return (tSHIFT_L);
269                 db_unread_char(c);
270                 break;
271             case '>':
272                 c = db_read_char();
273                 if (c == '>')
274                     return (tSHIFT_R);
275                 db_unread_char(c);
276                 break;
277             case -1:
278                 return (tEOF);
279         }
280         db_printf("Bad character\n");
281         db_flush_lex();
282         return (tEOF);
283 }