Merge from vendor branch NCURSES:
[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.4 2005/02/01 17:53:01 eirikn 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(c)
90         int c;
91 {
92         db_look_char = c;
93 }
94
95 static int      db_look_token = 0;
96
97 void
98 db_unread_token(int t)
99 {
100         db_look_token = t;
101 }
102
103 int
104 db_read_token(void)
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(void)
124 {
125         db_flush_line();
126         db_look_char = 0;
127         db_look_token = 0;
128 }
129
130 static 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                 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 }