db_lex.c revision 273265
12Sjlaskey/*-
26Sjlaskey * Mach Operating System
32Sjlaskey * Copyright (c) 1991,1990 Carnegie Mellon University
4877Sattila * All Rights Reserved.
52Sjlaskey *
62Sjlaskey * Permission to use, copy, modify and distribute this software and its
72Sjlaskey * documentation is hereby granted, provided that both the copyright
8877Sattila * notice and this permission notice appear in all copies of the
92Sjlaskey * software, derivative works or modified versions, and any portions
102Sjlaskey * thereof, and that both notices appear in supporting documentation.
112Sjlaskey *
122Sjlaskey * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
132Sjlaskey * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14877Sattila * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
152Sjlaskey *
162Sjlaskey * Carnegie Mellon requests users of this software to return to
172Sjlaskey *
18877Sattila *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
192Sjlaskey *  School of Computer Science
202Sjlaskey *  Carnegie Mellon University
212Sjlaskey *  Pittsburgh PA 15213-3890
222Sjlaskey *
232Sjlaskey * any improvements or extensions that they make and grant Carnegie the
242Sjlaskey * rights to redistribute these changes.
252Sjlaskey */
262Sjlaskey/*
272Sjlaskey *	Author: David B. Golub, Carnegie Mellon University
282Sjlaskey *	Date:	7/90
292Sjlaskey */
302Sjlaskey/*
312Sjlaskey * Lexical analyzer.
322Sjlaskey */
332Sjlaskey
342Sjlaskey#include <sys/cdefs.h>
352Sjlaskey__FBSDID("$FreeBSD: stable/10/sys/ddb/db_lex.c 273265 2014-10-18 19:22:59Z pfg $");
362Sjlaskey
372Sjlaskey#include <sys/param.h>
382Sjlaskey#include <sys/libkern.h>
392Sjlaskey
402Sjlaskey#include <ddb/ddb.h>
412Sjlaskey#include <ddb/db_lex.h>
422Sjlaskey
432Sjlaskeystatic char	db_line[DB_MAXLINE];
442Sjlaskeystatic char *	db_lp, *db_endlp;
452Sjlaskey
462Sjlaskeystatic int	db_lex(void);
472Sjlaskeystatic void 	db_flush_line(void);
482Sjlaskeystatic int 	db_read_char(void);
492Sjlaskeystatic void 	db_unread_char(int);
50278Sattila
512Sjlaskeyint
522Sjlaskeydb_read_line(void)
532Sjlaskey{
542Sjlaskey	int	i;
552Sjlaskey
562Sjlaskey	i = db_readline(db_line, sizeof(db_line));
572Sjlaskey	if (i == 0)
582Sjlaskey	    return (0);	/* EOI */
592Sjlaskey	db_lp = db_line;
602Sjlaskey	db_endlp = db_lp + i;
612Sjlaskey	return (i);
622Sjlaskey}
632Sjlaskey
642Sjlaskey/*
652Sjlaskey * Simulate a line of input into DDB.
66278Sattila */
672Sjlaskeyvoid
682Sjlaskeydb_inject_line(const char *command)
692Sjlaskey{
702Sjlaskey
712Sjlaskey	strlcpy(db_line, command, sizeof(db_line));
722Sjlaskey	db_lp = db_line;
732Sjlaskey	db_endlp = db_lp + strlen(command);
742Sjlaskey}
752Sjlaskey
762Sjlaskey/*
772Sjlaskey * In rare cases, we may want to pull the remainder of the line input
782Sjlaskey * verbatim, rather than lexing it.  For example, when assigning literal
792Sjlaskey * values associated with scripts.  In that case, return a static pointer to
802Sjlaskey * the current location in the input buffer.  The caller must be aware that
81278Sattila * the contents are not stable if other lex/input calls are made.
822Sjlaskey */
832Sjlaskeychar *
842Sjlaskeydb_get_line(void)
852Sjlaskey{
862Sjlaskey
872Sjlaskey	return (db_lp);
882Sjlaskey}
892Sjlaskey
902Sjlaskeystatic void
91278Sattiladb_flush_line()
922Sjlaskey{
932Sjlaskey	db_lp = db_line;
942Sjlaskey	db_endlp = db_line;
952Sjlaskey}
962Sjlaskey
972Sjlaskeystatic int	db_look_char = 0;
982Sjlaskey
992Sjlaskeystatic int
1002Sjlaskeydb_read_char(void)
1012Sjlaskey{
1022Sjlaskey	int	c;
1032Sjlaskey
1042Sjlaskey	if (db_look_char != 0) {
1052Sjlaskey	    c = db_look_char;
1062Sjlaskey	    db_look_char = 0;
107278Sattila	}
1082Sjlaskey	else if (db_lp >= db_endlp)
1092Sjlaskey	    c = -1;
1102Sjlaskey	else
1112Sjlaskey	    c = *db_lp++;
1122Sjlaskey	return (c);
1132Sjlaskey}
1142Sjlaskey
1152Sjlaskeystatic void
1162Sjlaskeydb_unread_char(c)
1172Sjlaskey	int c;
1182Sjlaskey{
1192Sjlaskey	db_look_char = c;
1202Sjlaskey}
1212Sjlaskey
1222Sjlaskeystatic int	db_look_token = 0;
1232Sjlaskey
1242Sjlaskeyvoid
1252Sjlaskeydb_unread_token(t)
1262Sjlaskey	int	t;
1272Sjlaskey{
1282Sjlaskey	db_look_token = t;
1292Sjlaskey}
1302Sjlaskey
1312Sjlaskeyint
1322Sjlaskeydb_read_token()
1332Sjlaskey{
134278Sattila	int	t;
1352Sjlaskey
1362Sjlaskey	if (db_look_token) {
1372Sjlaskey	    t = db_look_token;
1382Sjlaskey	    db_look_token = 0;
1392Sjlaskey	}
1402Sjlaskey	else
141278Sattila	    t = db_lex();
1422Sjlaskey	return (t);
1432Sjlaskey}
1442Sjlaskey
1452Sjlaskeydb_expr_t	db_tok_number;
1462Sjlaskeychar	db_tok_string[TOK_STRING_SIZE];
1472Sjlaskey
1482Sjlaskeydb_expr_t	db_radix = 16;
1492Sjlaskey
1502Sjlaskeyvoid
1512Sjlaskeydb_flush_lex(void)
1522Sjlaskey{
1532Sjlaskey	db_flush_line();
1542Sjlaskey	db_look_char = 0;
1552Sjlaskey	db_look_token = 0;
1562Sjlaskey}
157278Sattila
158278Sattilastatic int
1592Sjlaskeydb_lex(void)
1602Sjlaskey{
1612Sjlaskey	int	c;
1622Sjlaskey
1632Sjlaskey	c = db_read_char();
1642Sjlaskey	while (c <= ' ' || c > '~') {
1652Sjlaskey	    if (c == '\n' || c == -1)
1662Sjlaskey		return (tEOL);
167278Sattila	    c = db_read_char();
1682Sjlaskey	}
1692Sjlaskey
170278Sattila	if (c >= '0' && c <= '9') {
1712Sjlaskey	    /* number */
172278Sattila	    int	r, digit = 0;
1732Sjlaskey
1742Sjlaskey	    if (c > '0')
1752Sjlaskey		r = db_radix;
1762Sjlaskey	    else {
1772Sjlaskey		c = db_read_char();
1782Sjlaskey		if (c == 'O' || c == 'o')
1792Sjlaskey		    r = 8;
1802Sjlaskey		else if (c == 'T' || c == 't')
1812Sjlaskey		    r = 10;
1822Sjlaskey		else if (c == 'X' || c == 'x')
1832Sjlaskey		    r = 16;
1842Sjlaskey		else {
1852Sjlaskey		    r = db_radix;
1862Sjlaskey		    db_unread_char(c);
1872Sjlaskey		}
1882Sjlaskey		c = db_read_char();
1892Sjlaskey	    }
1902Sjlaskey	    db_tok_number = 0;
1912Sjlaskey	    for (;;) {
1922Sjlaskey		if (c >= '0' && c <= ((r == 8) ? '7' : '9'))
1932Sjlaskey		    digit = c - '0';
1942Sjlaskey		else if (r == 16 && ((c >= 'A' && c <= 'F') ||
1952Sjlaskey				     (c >= 'a' && c <= 'f'))) {
1962Sjlaskey		    if (c >= 'a')
1972Sjlaskey			digit = c - 'a' + 10;
1982Sjlaskey		    else if (c >= 'A')
1992Sjlaskey			digit = c - 'A' + 10;
2002Sjlaskey		}
2012Sjlaskey		else
2022Sjlaskey		    break;
2032Sjlaskey		db_tok_number = db_tok_number * r + digit;
2042Sjlaskey		c = db_read_char();
2052Sjlaskey	    }
2062Sjlaskey	    if ((c >= '0' && c <= '9') ||
2072Sjlaskey		(c >= 'A' && c <= 'Z') ||
2082Sjlaskey		(c >= 'a' && c <= 'z') ||
2092Sjlaskey		(c == '_'))
2102Sjlaskey	    {
2112Sjlaskey		db_error("Bad character in number\n");
2122Sjlaskey		db_flush_lex();
2132Sjlaskey		return (tEOF);
2142Sjlaskey	    }
2152Sjlaskey	    db_unread_char(c);
2162Sjlaskey	    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 == ':' || 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		return (tSEMI);
296	    case '<':
297		c = db_read_char();
298		if (c == '<')
299		    return (tSHIFT_L);
300		db_unread_char(c);
301		break;
302	    case '>':
303		c = db_read_char();
304		if (c == '>')
305		    return (tSHIFT_R);
306		db_unread_char(c);
307		break;
308	    case -1:
309		return (tEOF);
310	}
311	db_printf("Bad character\n");
312	db_flush_lex();
313	return (tEOF);
314}
315