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 #include <sys/systm.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 /* 122 * Convert the number to a string in the current radix. 123 * This replaces the non-standard %r kprintf() format. 124 */ 125 126 char * 127 db_num_to_str(db_expr_t val) 128 { 129 130 /* 131 * 2 chars for "0x", 1 for a sign ("-") 132 * up to 21 chars for a 64-bit number: 133 * % echo 2^64 | bc | wc -c 134 * 21 135 * and 1 char for a terminal NUL 136 * 2+1+21+1 => 25 137 */ 138 static char buf[25]; 139 140 if (db_radix == 16) 141 ksnprintf(buf, sizeof(buf), "%" DDB_EXPR_FMT "x", val); 142 else if (db_radix == 8) 143 ksnprintf(buf, sizeof(buf), "%" DDB_EXPR_FMT "o", val); 144 else 145 ksnprintf(buf, sizeof(buf), "%" DDB_EXPR_FMT "u", val); 146 147 return (buf); 148 } 149 150 void 151 db_flush_lex(void) 152 { 153 db_flush_line(); 154 db_look_char = 0; 155 db_look_token = 0; 156 } 157 158 static int 159 db_lex(void) 160 { 161 int c; 162 163 c = db_read_char(); 164 while (c <= ' ' || c > '~') { 165 if (c == '\n' || c == -1) 166 return (tEOL); 167 c = db_read_char(); 168 } 169 170 if (c >= '0' && c <= '9') { 171 /* number */ 172 int r, digit = 0; 173 174 if (c > '0') 175 r = db_radix; 176 else { 177 c = db_read_char(); 178 if (c == 'O' || c == 'o') 179 r = 8; 180 else if (c == 'T' || c == 't') 181 r = 10; 182 else if (c == 'X' || c == 'x') 183 r = 16; 184 else { 185 r = db_radix; 186 db_unread_char(c); 187 } 188 c = db_read_char(); 189 } 190 db_tok_number = 0; 191 for (;;) { 192 if (c >= '0' && c <= ((r == 8) ? '7' : '9')) 193 digit = c - '0'; 194 else if (r == 16 && ((c >= 'A' && c <= 'F') || 195 (c >= 'a' && c <= 'f'))) { 196 if (c >= 'a') 197 digit = c - 'a' + 10; 198 else if (c >= 'A') 199 digit = c - 'A' + 10; 200 } 201 else 202 break; 203 db_tok_number = db_tok_number * r + digit; 204 c = db_read_char(); 205 } 206 if ((c >= '0' && c <= '9') || 207 (c >= 'A' && c <= 'Z') || 208 (c >= 'a' && c <= 'z') || 209 (c == '_')) 210 { 211 db_error("Bad character in number\n"); 212 db_flush_lex(); 213 return (tEOF); 214 } 215 db_unread_char(c); 216 return (tNUMBER); 217 } 218 if ((c >= 'A' && c <= 'Z') || 219 (c >= 'a' && c <= 'z') || 220 c == '_' || c == '\\') 221 { 222 /* string */ 223 char *cp; 224 225 cp = db_tok_string; 226 if (c == '\\') { 227 c = db_read_char(); 228 if (c == '\n' || c == -1) 229 db_error("Bad escape\n"); 230 } 231 *cp++ = c; 232 while (1) { 233 c = db_read_char(); 234 if ((c >= 'A' && c <= 'Z') || 235 (c >= 'a' && c <= 'z') || 236 (c >= '0' && c <= '9') || 237 c == '_' || c == '\\' || c == ':') 238 { 239 if (c == '\\') { 240 c = db_read_char(); 241 if (c == '\n' || c == -1) 242 db_error("Bad escape\n"); 243 } 244 *cp++ = c; 245 if (cp == db_tok_string+sizeof(db_tok_string)) { 246 db_error("String too long\n"); 247 db_flush_lex(); 248 return (tEOF); 249 } 250 continue; 251 } 252 else { 253 *cp = '\0'; 254 break; 255 } 256 } 257 db_unread_char(c); 258 return (tIDENT); 259 } 260 261 switch (c) { 262 case '+': 263 return (tPLUS); 264 case '-': 265 return (tMINUS); 266 case '.': 267 c = db_read_char(); 268 if (c == '.') 269 return (tDOTDOT); 270 db_unread_char(c); 271 return (tDOT); 272 case '*': 273 return (tSTAR); 274 case '/': 275 return (tSLASH); 276 case '=': 277 return (tEQ); 278 case '%': 279 return (tPCT); 280 case '#': 281 return (tHASH); 282 case '(': 283 return (tLPAREN); 284 case ')': 285 return (tRPAREN); 286 case ',': 287 return (tCOMMA); 288 case '"': 289 return (tDITTO); 290 case '$': 291 return (tDOLLAR); 292 case '!': 293 return (tEXCL); 294 case '<': 295 c = db_read_char(); 296 if (c == '<') 297 return (tSHIFT_L); 298 db_unread_char(c); 299 break; 300 case '>': 301 c = db_read_char(); 302 if (c == '>') 303 return (tSHIFT_R); 304 db_unread_char(c); 305 break; 306 case -1: 307 return (tEOF); 308 } 309 db_printf("Bad character\n"); 310 db_flush_lex(); 311 return (tEOF); 312 } 313