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$ 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 } 285