Initial import from FreeBSD RELENG_4:
[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  */
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
41 static char     db_line[120];
42 static char *   db_lp, *db_endlp;
43
44 static int      db_lex __P((void));
45 static void     db_flush_line __P((void));
46 static int      db_read_char __P((void));
47 static void     db_unread_char __P((int));
48
49 int
50 db_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
62 static void
63 db_flush_line()
64 {
65         db_lp = db_line;
66         db_endlp = db_line;
67 }
68
69 static int      db_look_char = 0;
70
71 static int
72 db_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
87 static void
88 db_unread_char(c)
89         int c;
90 {
91         db_look_char = c;
92 }
93
94 static int      db_look_token = 0;
95
96 void
97 db_unread_token(t)
98         int     t;
99 {
100         db_look_token = t;
101 }
102
103 int
104 db_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
117 db_expr_t       db_tok_number;
118 char    db_tok_string[TOK_STRING_SIZE];
119
120 db_expr_t       db_radix = 16;
121
122 void
123 db_flush_lex()
124 {
125         db_flush_line();
126         db_look_char = 0;
127         db_look_token = 0;
128 }
129
130 static int
131 db_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 == ':')
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 }