1 1.27 riastrad /* $NetBSD: db_lex.c,v 1.27 2022/08/30 22:37:03 riastradh Exp $ */ 2 1.4 cgd 3 1.16 simonb /* 4 1.1 cgd * Mach Operating System 5 1.1 cgd * Copyright (c) 1991,1990 Carnegie Mellon University 6 1.1 cgd * All Rights Reserved. 7 1.16 simonb * 8 1.1 cgd * Permission to use, copy, modify and distribute this software and its 9 1.1 cgd * documentation is hereby granted, provided that both the copyright 10 1.1 cgd * notice and this permission notice appear in all copies of the 11 1.1 cgd * software, derivative works or modified versions, and any portions 12 1.1 cgd * thereof, and that both notices appear in supporting documentation. 13 1.16 simonb * 14 1.11 pk * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 1.1 cgd * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 1.1 cgd * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 1.16 simonb * 18 1.1 cgd * Carnegie Mellon requests users of this software to return to 19 1.16 simonb * 20 1.1 cgd * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 21 1.1 cgd * School of Computer Science 22 1.1 cgd * Carnegie Mellon University 23 1.1 cgd * Pittsburgh PA 15213-3890 24 1.16 simonb * 25 1.1 cgd * any improvements or extensions that they make and grant Carnegie the 26 1.1 cgd * rights to redistribute these changes. 27 1.2 cgd * 28 1.1 cgd * Author: David B. Golub, Carnegie Mellon University 29 1.1 cgd * Date: 7/90 30 1.1 cgd */ 31 1.3 mycroft 32 1.1 cgd /* 33 1.1 cgd * Lexical analyzer. 34 1.1 cgd */ 35 1.15 lukem 36 1.15 lukem #include <sys/cdefs.h> 37 1.27 riastrad __KERNEL_RCSID(0, "$NetBSD: db_lex.c,v 1.27 2022/08/30 22:37:03 riastradh Exp $"); 38 1.15 lukem 39 1.5 mycroft #include <sys/param.h> 40 1.13 soren #include <sys/systm.h> 41 1.23 uwe #include <sys/cpu.h> 42 1.5 mycroft 43 1.21 ad #include <ddb/ddb.h> 44 1.1 cgd 45 1.16 simonb db_expr_t db_tok_number; 46 1.16 simonb char db_tok_string[TOK_STRING_SIZE]; 47 1.16 simonb 48 1.20 yamt static char db_line[DB_LINE_MAXLEN]; 49 1.19 yamt static const char *db_lp; 50 1.19 yamt static const char *db_endlp; 51 1.16 simonb 52 1.16 simonb static int db_look_char = 0; 53 1.16 simonb static int db_look_token = 0; 54 1.16 simonb 55 1.16 simonb static void db_flush_line(void); 56 1.16 simonb static int db_read_char(void); 57 1.16 simonb static void db_unread_char(int); 58 1.16 simonb static int db_lex(void); 59 1.1 cgd 60 1.1 cgd int 61 1.16 simonb db_read_line(void) 62 1.1 cgd { 63 1.1 cgd int i; 64 1.1 cgd 65 1.25 ad #ifdef _KERNEL 66 1.25 ad /* 67 1.25 ad * crash(8) prints the prompt using libedit. That's why we used to 68 1.25 ad * print it in db_readline(). But now people are using db_read_line() 69 1.25 ad * for general purpose input, so.. 70 1.25 ad */ 71 1.23 uwe #ifdef MULTIPROCESSOR 72 1.23 uwe db_printf("db{%ld}> ", (long)cpu_number()); 73 1.23 uwe #else 74 1.23 uwe db_printf("db> "); 75 1.23 uwe #endif 76 1.25 ad #endif 77 1.1 cgd i = db_readline(db_line, sizeof(db_line)); 78 1.1 cgd if (i == 0) 79 1.16 simonb return (0); /* EOI */ 80 1.19 yamt db_set_line(db_line, db_line + i); 81 1.1 cgd return (i); 82 1.1 cgd } 83 1.1 cgd 84 1.19 yamt void 85 1.19 yamt db_set_line(const char *sp, const char *ep) 86 1.19 yamt { 87 1.19 yamt 88 1.19 yamt db_lp = sp; 89 1.19 yamt db_endlp = ep; 90 1.19 yamt } 91 1.19 yamt 92 1.26 uwe void 93 1.26 uwe db_get_line(const char **psp, const char **pep) 94 1.26 uwe { 95 1.26 uwe 96 1.26 uwe if (psp != NULL) 97 1.26 uwe *psp = db_lp; 98 1.26 uwe if (pep != NULL) 99 1.26 uwe *pep = db_endlp; 100 1.26 uwe } 101 1.26 uwe 102 1.16 simonb static void 103 1.16 simonb db_flush_line(void) 104 1.1 cgd { 105 1.16 simonb 106 1.1 cgd db_lp = db_line; 107 1.1 cgd db_endlp = db_line; 108 1.1 cgd } 109 1.1 cgd 110 1.16 simonb static int 111 1.16 simonb db_read_char(void) 112 1.1 cgd { 113 1.1 cgd int c; 114 1.1 cgd 115 1.1 cgd if (db_look_char != 0) { 116 1.16 simonb c = db_look_char; 117 1.16 simonb db_look_char = 0; 118 1.1 cgd } 119 1.1 cgd else if (db_lp >= db_endlp) 120 1.16 simonb c = -1; 121 1.16 simonb else 122 1.16 simonb c = *db_lp++; 123 1.1 cgd return (c); 124 1.1 cgd } 125 1.1 cgd 126 1.16 simonb static void 127 1.16 simonb db_unread_char(int c) 128 1.1 cgd { 129 1.16 simonb 130 1.1 cgd db_look_char = c; 131 1.1 cgd } 132 1.1 cgd 133 1.1 cgd void 134 1.16 simonb db_unread_token(int t) 135 1.1 cgd { 136 1.16 simonb 137 1.1 cgd db_look_token = t; 138 1.1 cgd } 139 1.1 cgd 140 1.1 cgd int 141 1.16 simonb db_read_token(void) 142 1.1 cgd { 143 1.1 cgd int t; 144 1.1 cgd 145 1.1 cgd if (db_look_token) { 146 1.16 simonb t = db_look_token; 147 1.16 simonb db_look_token = 0; 148 1.1 cgd } 149 1.1 cgd else 150 1.16 simonb t = db_lex(); 151 1.1 cgd return (t); 152 1.1 cgd } 153 1.1 cgd 154 1.1 cgd int db_radix = 16; 155 1.12 jhawk 156 1.12 jhawk /* 157 1.12 jhawk * Convert the number to a string in the current radix. 158 1.12 jhawk * This replaces the non-standard %n printf() format. 159 1.12 jhawk */ 160 1.16 simonb 161 1.12 jhawk char * 162 1.16 simonb db_num_to_str(db_expr_t val) 163 1.12 jhawk { 164 1.17 enami 165 1.16 simonb /* 166 1.12 jhawk * 2 chars for "0x", 1 for a sign ("-") 167 1.12 jhawk * up to 21 chars for a 64-bit number: 168 1.12 jhawk * % echo 2^64 | bc | wc -c 169 1.12 jhawk * 21 170 1.12 jhawk * and 1 char for a terminal NUL 171 1.12 jhawk * 2+1+21+1 => 25 172 1.12 jhawk */ 173 1.12 jhawk static char buf[25]; 174 1.12 jhawk 175 1.27 riastrad db_num_to_strbuf(val, buf, sizeof(buf)); 176 1.27 riastrad 177 1.27 riastrad return (buf); 178 1.27 riastrad } 179 1.27 riastrad 180 1.27 riastrad void 181 1.27 riastrad db_num_to_strbuf(db_expr_t val, char *buf, size_t len) 182 1.27 riastrad { 183 1.27 riastrad 184 1.12 jhawk if (db_radix == 16) 185 1.27 riastrad snprintf(buf, len, "%" DDB_EXPR_FMT "x", val); 186 1.12 jhawk else if (db_radix == 8) 187 1.27 riastrad snprintf(buf, len, "%" DDB_EXPR_FMT "o", val); 188 1.12 jhawk else 189 1.27 riastrad snprintf(buf, len, "%" DDB_EXPR_FMT "u", val); 190 1.12 jhawk } 191 1.1 cgd 192 1.1 cgd void 193 1.16 simonb db_flush_lex(void) 194 1.1 cgd { 195 1.16 simonb 196 1.1 cgd db_flush_line(); 197 1.1 cgd db_look_char = 0; 198 1.1 cgd db_look_token = 0; 199 1.1 cgd } 200 1.1 cgd 201 1.16 simonb static int 202 1.16 simonb db_lex(void) 203 1.1 cgd { 204 1.1 cgd int c; 205 1.1 cgd 206 1.1 cgd c = db_read_char(); 207 1.1 cgd while (c <= ' ' || c > '~') { 208 1.16 simonb if (c == '\n' || c == -1) 209 1.16 simonb return (tEOL); 210 1.16 simonb c = db_read_char(); 211 1.1 cgd } 212 1.1 cgd 213 1.1 cgd if (c >= '0' && c <= '9') { 214 1.16 simonb /* number */ 215 1.16 simonb db_expr_t r, digit = 0; 216 1.1 cgd 217 1.16 simonb if (c > '0') 218 1.16 simonb r = db_radix; 219 1.1 cgd else { 220 1.16 simonb c = db_read_char(); 221 1.16 simonb if (c == 'O' || c == 'o') 222 1.16 simonb r = 8; 223 1.16 simonb else if (c == 'T' || c == 't') 224 1.16 simonb r = 10; 225 1.16 simonb else if (c == 'X' || c == 'x') 226 1.16 simonb r = 16; 227 1.16 simonb else { 228 1.16 simonb r = db_radix; 229 1.16 simonb db_unread_char(c); 230 1.16 simonb } 231 1.16 simonb c = db_read_char(); 232 1.1 cgd } 233 1.16 simonb db_tok_number = 0; 234 1.16 simonb for (;;) { 235 1.16 simonb if (c >= '0' && c <= ((r == 8) ? '7' : '9')) 236 1.16 simonb digit = c - '0'; 237 1.24 rin else if (r == 16) { 238 1.24 rin if (c >= 'A' && c <= 'F') 239 1.24 rin digit = c - 'A' + 10; 240 1.24 rin else if (c >= 'a' && c <= 'f') 241 1.16 simonb digit = c - 'a' + 10; 242 1.24 rin else 243 1.24 rin break; 244 1.24 rin } else 245 1.16 simonb break; 246 1.16 simonb db_tok_number = db_tok_number * r + digit; 247 1.16 simonb c = db_read_char(); 248 1.16 simonb } 249 1.16 simonb if ((c >= '0' && c <= '9') || 250 1.16 simonb (c >= 'A' && c <= 'Z') || 251 1.16 simonb (c >= 'a' && c <= 'z') || 252 1.16 simonb (c == '_')) { 253 1.16 simonb db_error("Bad character in number\n"); 254 1.16 simonb /*NOTREACHED*/ 255 1.1 cgd } 256 1.16 simonb db_unread_char(c); 257 1.16 simonb return (tNUMBER); 258 1.1 cgd } 259 1.1 cgd if ((c >= 'A' && c <= 'Z') || 260 1.1 cgd (c >= 'a' && c <= 'z') || 261 1.16 simonb c == '_' || c == '\\') { 262 1.16 simonb /* string */ 263 1.16 simonb char *cp; 264 1.1 cgd 265 1.16 simonb cp = db_tok_string; 266 1.16 simonb if (c == '\\') { 267 1.1 cgd c = db_read_char(); 268 1.7 mycroft if (c == '\n' || c == -1) { 269 1.16 simonb db_error("Bad escape\n"); 270 1.16 simonb /*NOTREACHED*/ 271 1.7 mycroft } 272 1.1 cgd } 273 1.16 simonb *cp++ = c; 274 1.16 simonb while (1) { 275 1.16 simonb c = db_read_char(); 276 1.16 simonb if ((c >= 'A' && c <= 'Z') || 277 1.16 simonb (c >= 'a' && c <= 'z') || 278 1.16 simonb (c >= '0' && c <= '9') || 279 1.16 simonb c == '_' || c == '\\' || c == ':') { 280 1.16 simonb if (c == '\\') { 281 1.16 simonb c = db_read_char(); 282 1.16 simonb if (c == '\n' || c == -1) { 283 1.16 simonb db_error("Bad escape\n"); 284 1.16 simonb /*NOTREACHED*/ 285 1.16 simonb } 286 1.16 simonb } 287 1.16 simonb *cp++ = c; 288 1.16 simonb if (cp == db_tok_string+sizeof(db_tok_string)) { 289 1.16 simonb db_error("String too long\n"); 290 1.16 simonb /*NOTREACHED*/ 291 1.16 simonb } 292 1.16 simonb continue; 293 1.16 simonb } else { 294 1.16 simonb *cp = '\0'; 295 1.16 simonb break; 296 1.16 simonb } 297 1.1 cgd } 298 1.16 simonb db_unread_char(c); 299 1.16 simonb return (tIDENT); 300 1.1 cgd } 301 1.1 cgd 302 1.1 cgd switch (c) { 303 1.16 simonb case '+': 304 1.1 cgd return (tPLUS); 305 1.16 simonb case '-': 306 1.1 cgd return (tMINUS); 307 1.16 simonb case '.': 308 1.1 cgd c = db_read_char(); 309 1.1 cgd if (c == '.') 310 1.16 simonb return (tDOTDOT); 311 1.1 cgd db_unread_char(c); 312 1.1 cgd return (tDOT); 313 1.16 simonb case '*': 314 1.1 cgd return (tSTAR); 315 1.16 simonb case '/': 316 1.1 cgd return (tSLASH); 317 1.16 simonb case '=': 318 1.1 cgd return (tEQ); 319 1.16 simonb case '%': 320 1.1 cgd return (tPCT); 321 1.16 simonb case '#': 322 1.1 cgd return (tHASH); 323 1.16 simonb case '(': 324 1.1 cgd return (tLPAREN); 325 1.16 simonb case ')': 326 1.1 cgd return (tRPAREN); 327 1.16 simonb case ',': 328 1.1 cgd return (tCOMMA); 329 1.16 simonb case '"': 330 1.1 cgd return (tDITTO); 331 1.16 simonb case '$': 332 1.1 cgd return (tDOLLAR); 333 1.16 simonb case '!': 334 1.1 cgd return (tEXCL); 335 1.16 simonb case '<': 336 1.1 cgd c = db_read_char(); 337 1.1 cgd if (c == '<') 338 1.16 simonb return (tSHIFT_L); 339 1.1 cgd db_unread_char(c); 340 1.1 cgd break; 341 1.16 simonb case '>': 342 1.1 cgd c = db_read_char(); 343 1.1 cgd if (c == '>') 344 1.16 simonb return (tSHIFT_R); 345 1.1 cgd db_unread_char(c); 346 1.1 cgd break; 347 1.16 simonb case -1: 348 1.1 cgd return (tEOF); 349 1.1 cgd } 350 1.1 cgd db_printf("Bad character\n"); 351 1.1 cgd db_flush_lex(); 352 1.1 cgd return (tEOF); 353 1.1 cgd } 354 1.21 ad 355 1.21 ad /* 356 1.21 ad * Utility routine - discard tokens through end-of-line. 357 1.21 ad */ 358 1.21 ad void 359 1.21 ad db_skip_to_eol(void) 360 1.21 ad { 361 1.21 ad int t; 362 1.21 ad 363 1.21 ad do { 364 1.21 ad t = db_read_token(); 365 1.21 ad } while (t != tEOL); 366 1.21 ad } 367 1.21 ad 368 1.21 ad void 369 1.21 ad db_error(const char *s) 370 1.21 ad { 371 1.21 ad 372 1.21 ad if (s) 373 1.21 ad db_printf("%s", s); 374 1.21 ad db_flush_lex(); 375 1.21 ad longjmp(db_recover); 376 1.21 ad } 377