xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_lex.l (revision 4585130b259133a26efae68275dbe56b08366deb)
1 %pointer	/* Make yytext a pointer, not an array */
2 
3 %{
4 /*
5  * CDDL HEADER START
6  *
7  * The contents of this file are subject to the terms of the
8  * Common Development and Distribution License (the "License").
9  * You may not use this file except in compliance with the License.
10  *
11  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
12  * or http://www.opensolaris.org/os/licensing.
13  * See the License for the specific language governing permissions
14  * and limitations under the License.
15  *
16  * When distributing Covered Code, include this CDDL HEADER in each
17  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
18  * If applicable, add the following below this CDDL HEADER, with the
19  * fields enclosed by brackets "[]" replaced with your own identifying
20  * information: Portions Copyright [yyyy] [name of copyright owner]
21  *
22  * CDDL HEADER END
23  *
24  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*
29  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/isa_defs.h>
34 
35 #include <strings.h>
36 #include <stdarg.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <errno.h>
40 
41 #include <mdb/mdb_types.h>
42 #include <mdb/mdb_debug.h>
43 #include <mdb/mdb_nv.h>
44 #include <mdb/mdb_lex.h>
45 #include <mdb/mdb_frame.h>
46 #include <mdb/mdb_string.h>
47 #include <mdb/mdb_stdlib.h>
48 #include <mdb/mdb_err.h>
49 #include <mdb/mdb.h>
50 
51 #include "mdb_grammar.h"
52 
53 /*
54  * lex hardcodes yyin and yyout to stdin and stdout, respectively, before we get
55  * control.  We've redirected printf and fprintf (see mdb_lex.h) to yyprintf and
56  * yyfprintf, which ignore the FILE * provided by yyout.  __iob-based stdin and
57  * stdout are useless in kmdb, since we don't have stdio.  We define __iob here
58  * to shut the linker up.
59  */
60 #ifdef _KMDB
61 FILE __iob[_NFILE];
62 #endif
63 
64 /*
65  * We need to undefine lex's input, unput, and output macros so that references
66  * to these call the functions we provide at the end of this source file,
67  * instead of the default versions based on libc's stdio.
68  */
69 #ifdef input
70 #undef input
71 #endif
72 
73 #ifdef unput
74 #undef unput
75 #endif
76 
77 #ifdef output
78 #undef output
79 #endif
80 
81 static int input(void);
82 static void unput(int);
83 static void output(int);
84 
85 static void string_unquote(char *);
86 
87 extern int yydebug;
88 
89 /*
90  * This will prevent lex from trying to malloc() and resize our yytext variable,
91  * instead it will just print out an error message and exit(), which seems
92  * a lesser of two evils.
93  */
94 #define YYISARRAY
95 
96 %}
97 
98 %o	9000
99 %a	5000
100 
101 %s	S_SHELLCMD
102 %s	S_INITIAL
103 %s	S_FMTLIST
104 %s	S_ARGLIST
105 %s	S_EXPR
106 
107 RGX_CMD_CHAR	[?%@A-Z\^_`a-z]
108 RGX_SYMBOL	[a-zA-Z_.][0-9a-zA-Z_.`]*
109 RGX_SIMPLE_CHAR	[^ \t\n;!|"'\$]
110 RGX_CHR_SEQ	([^'\n]|\\[^'\n]|\\')*
111 RGX_STR_SEQ	([^"\\\n]|\\[^"\n]|\\\")*
112 RGX_COMMENT	"//".*\n
113 
114 %%
115 
116 <S_INITIAL>{RGX_COMMENT}	|
117 <S_FMTLIST>{RGX_COMMENT}	|
118 <S_ARGLIST>{RGX_COMMENT}	{
119 		/*
120 		 * Comments are legal in these three states -- if we see one
121 		 * eat the line and return the newline character.
122 		 */
123 		BEGIN(S_INITIAL);
124 		return ('\n');
125 	}
126 
127 <S_INITIAL>"=="	|
128 <S_EXPR>"=="	return (MDB_TOK_EQUAL); /* Equality operator */
129 
130 <S_INITIAL>"!="	|
131 <S_EXPR>"!="	return (MDB_TOK_NOTEQUAL); /* Inequality operator */
132 
133 <S_INITIAL>"!"	|
134 <S_FMTLIST>"!"	|
135 <S_ARGLIST>"!"	{
136 		/*
137 		 * Shell escapes are legal in all of these states -- switch to
138 		 * the shell command state and return the ! character.
139 		 */
140 		BEGIN(S_SHELLCMD);
141 		return (yytext[0]);
142 	}
143 
144 <S_FMTLIST>"|"	|
145 <S_ARGLIST>"|"	{
146 		/*
147 		 * Pipelines can appear in any of these states -- switch to
148 		 * the initial state and return the | character.
149 		 */
150 		BEGIN(S_INITIAL);
151 		return (yytext[0]);
152 	}
153 
154 <S_SHELLCMD>[^;\n]+	{
155 		/*
156 		 * Once in the shell-command state, we return all remaining
157 		 * characters up to a newline or ';' delimiter as a single
158 		 * string which will be passed to $SHELL -c.
159 		 */
160 		yylval.l_string = strdup(yytext);
161 		BEGIN(S_INITIAL);
162 		return (MDB_TOK_STRING);
163 	}
164 
165 <S_INITIAL>"::"{RGX_SYMBOL}	{
166 		/*
167 		 * Verb ::command-name -- lookup the correspond dcmd and
168 		 * switch to the argument list state.
169 		 */
170 		if ((yylval.l_dcmd = mdb_dcmd_lookup(yytext + 2)) == NULL)
171 			yyperror("invalid command '%s'", yytext);
172 
173 		BEGIN(S_ARGLIST);
174 		return (MDB_TOK_DCMD);
175 	}
176 
177 <S_INITIAL>"$<<"|"$<"|"$>"	|
178 <S_INITIAL>[\$:]{RGX_CMD_CHAR}	{
179 		/*
180 		 * Old-style :c or $c command -- lookup the corresponding dcmd
181 		 * and switch to the argument list state.
182 		 */
183 		if ((yylval.l_dcmd = mdb_dcmd_lookup(yytext)) == NULL)
184 			yyperror("invalid command '%s'", yytext);
185 
186 		BEGIN(S_ARGLIST);
187 		return (MDB_TOK_DCMD);
188 	}
189 
190 <S_INITIAL>">/"[a-zA-Z0-9]"/"	{
191 		/*
192 		 * Variable assignment with size cast -- append the cast letter
193 		 * to the argument list, and switch to the argument list state.
194 		 */
195 		mdb_arg_t arg;
196 
197 		arg.a_un.a_char = yytext[2];
198 		arg.a_type = MDB_TYPE_CHAR;
199 
200 		mdb_argvec_append(&mdb.m_frame->f_argvec, &arg);
201 		yylval.l_dcmd = mdb_dcmd_lookup(">");
202 
203 		BEGIN(S_ARGLIST);
204 		return (MDB_TOK_DCMD);
205 	}
206 
207 <S_INITIAL>">"	{
208 		/*
209 		 * Variable assignment -- switch to the argument list state.
210 		 */
211 		yylval.l_dcmd = mdb_dcmd_lookup(yytext);
212 		BEGIN(S_ARGLIST);
213 		return (MDB_TOK_DCMD);
214 	}
215 
216 <S_INITIAL>[/\\?][ \t]*[vwWZlLM]	{
217 		/*
218 		 * Format verb followed by write or match signifier -- switch
219 		 * to the value list state and return the verb character.  We
220 		 * also append the actual format character to the arg list.
221 		 */
222 		mdb_arg_t arg;
223 
224 		arg.a_un.a_char = yytext[yyleng - 1];
225 		arg.a_type = MDB_TYPE_CHAR;
226 
227 		mdb_argvec_append(&mdb.m_frame->f_argvec, &arg);
228 
229 		BEGIN(S_ARGLIST);
230 		return yytext[0];
231 	}
232 
233 <S_INITIAL>[/\\@?=]	{
234 		/*
235 		 * Format verb -- switch to the format list state and return
236 		 * the actual verb character verbatim.
237 		 */
238 		BEGIN(S_FMTLIST);
239 		return (yytext[0]);
240 	}
241 
242 <S_INITIAL>'{RGX_CHR_SEQ}$	|
243 <S_EXPR>'{RGX_CHR_SEQ}$		yyerror("syntax error: ' unmatched");
244 
245 <S_INITIAL>'{RGX_CHR_SEQ}' 	|
246 <S_EXPR>'{RGX_CHR_SEQ}'		{
247 		char *s, *p, *q;
248 		size_t nbytes;
249 
250 		/*
251 		 * If the character sequence is zero-length, return 0.
252 		 */
253 		if (yyleng == 2) {
254 			yylval.l_immediate = 0;
255 			return (MDB_TOK_IMMEDIATE);
256 		}
257 
258 		s = yytext + 1;			/* Skip past initial quote */
259 		yytext[yyleng - 1] = '\0';	/* Overwrite final quote */
260 		nbytes = stresc2chr(s);		/* Convert escapes */
261 		yylval.l_immediate = 0;		/* Initialize token value */
262 
263 		if (nbytes > sizeof (uintmax_t)) {
264 			yyerror("character constant may not exceed %lu bytes\n",
265 			    (ulong_t)sizeof (uintmax_t));
266 		}
267 
268 #ifdef _LITTLE_ENDIAN
269 		p = ((char*)&yylval.l_immediate) + nbytes - 1;
270 
271 		for (q = s; nbytes != 0; nbytes--)
272 			*p-- = *q++;
273 #else
274 		bcopy(s, ((char *)&yylval.l_immediate) +
275 		    sizeof (uintmax_t) - nbytes, nbytes);
276 #endif
277 		return (MDB_TOK_IMMEDIATE);
278 	}
279 
280 \"{RGX_STR_SEQ}$	yyerror("syntax error: \" unmatched");
281 
282 \"{RGX_STR_SEQ}\"	{
283 		/*
284 		 * Quoted string -- convert C escape sequences and return the
285 		 * string as a token.
286 		 */
287 		yylval.l_string = strndup(yytext + 1, yyleng - 2);
288 		(void) stresc2chr(yylval.l_string);
289 		return (MDB_TOK_STRING);
290 	}
291 
292 <S_ARGLIST>"$["	|
293 <S_FMTLIST>"$["	{
294 		/*
295 		 * Start of expression -- begin expression state and save the
296 		 * current state so we can return at the end of the expression.
297 		 */
298 		mdb.m_frame->f_oldstate = YYSTATE;
299 		BEGIN(S_EXPR);
300 		return (MDB_TOK_LEXPR);
301 	}
302 
303 <S_ARGLIST>{RGX_SIMPLE_CHAR}*("'"{RGX_CHR_SEQ}"'"|\"{RGX_STR_SEQ}\"|{RGX_SIMPLE_CHAR}+)* {
304 		/*
305 		 * String token -- create a copy of the string and return it.
306 		 * We need to handle embedded single and double-quote pairs,
307 		 * which overcomplicates this slightly.
308 		 */
309 		yylval.l_string = strdup(yytext);
310 		string_unquote(yylval.l_string);
311 		return (MDB_TOK_STRING);
312 	}
313 
314 <S_FMTLIST>[0-9]+	{
315 		/*
316 		 * Immediate value -- in the format list, all immediates
317 		 * are assumed to be in decimal.
318 		 */
319 		yylval.l_immediate = mdb_strtonum(yytext, 10);
320 		return (MDB_TOK_IMMEDIATE);
321 	}
322 
323 <S_FMTLIST>{RGX_SIMPLE_CHAR}	{
324 		/*
325 		 * Non-meta character -- in the format list, we return each
326 		 * character as a separate token to be added as an argument.
327 		 */
328 		yylval.l_char = yytext[0];
329 		return (MDB_TOK_CHAR);
330 	}
331 
332 <S_EXPR>";"|"!"|\n	{
333 		/*
334 		 * In the expression state only, we cannot see a command
335 		 * delimiter or shell escape before we end the expression.
336 		 */
337 		yyerror("syntax error: $[ unmatched");
338 	}
339 
340 <S_EXPR>"]"	{
341 		/*
342 		 * End of expression state.  Restore the state we were in
343 		 * before the "$[" which started this expression.
344 		 */
345 		BEGIN(mdb.m_frame->f_oldstate);
346 		return (MDB_TOK_REXPR);
347 	}
348 
349 <S_INITIAL>"<"{RGX_SYMBOL}	|
350 <S_INITIAL>"<"[0-9]		|
351 <S_EXPR>"<"{RGX_SYMBOL}		|
352 <S_EXPR>"<"[0-9]	{
353 		/*
354 		 * Variable reference -- lookup the variable and return a
355 		 * pointer to it.  Referencing undefined variables is an error.
356 		 */
357 		yylval.l_var = mdb_nv_lookup(&mdb.m_nv, &yytext[1]);
358 
359 		if (yylval.l_var == NULL)
360 			yyerror("variable '%s' is not defined", &yytext[1]);
361 
362 		return (MDB_TOK_VAR_REF);
363 	}
364 
365 <S_INITIAL>"<<"	|
366 <S_EXPR>"<<"	return (MDB_TOK_LSHIFT); /* Logical shift left operator */
367 
368 <S_INITIAL>">>"	|
369 <S_EXPR>">>"	return (MDB_TOK_RSHIFT); /* Logical shift right operator */
370 
371 <S_INITIAL>"*/"[a-zA-Z0-9]"/"	|
372 <S_EXPR>"*/"[a-zA-Z0-9]"/"	{
373 		switch (yytext[2]) {
374 			case 'c': case '1':
375 				return (MDB_TOK_COR1_DEREF);
376 			case 's': case '2':
377 				return (MDB_TOK_COR2_DEREF);
378 			case 'i': case '4':
379 #ifdef _ILP32
380 			case 'l':
381 #endif
382 				return (MDB_TOK_COR4_DEREF);
383 #ifdef _LP64
384 			case 'l':
385 #endif
386 			case '8':
387 				return (MDB_TOK_COR8_DEREF);
388 		}
389 		yyerror("invalid cast -- %s\n", yytext);
390 	}
391 
392 <S_INITIAL>"%/"[a-zA-Z0-9]"/"	|
393 <S_EXPR>"%/"[a-zA-Z0-9]"/"	{
394 		switch (yytext[2]) {
395 			case 'c': case '1':
396 				return (MDB_TOK_OBJ1_DEREF);
397 			case 's': case '2':
398 				return (MDB_TOK_OBJ2_DEREF);
399 			case 'i': case '4':
400 #ifdef _ILP32
401 			case 'l':
402 #endif
403 				return (MDB_TOK_OBJ4_DEREF);
404 #ifdef _LP64
405 			case 'l':
406 #endif
407 			case '8':
408 				return (MDB_TOK_OBJ8_DEREF);
409 		}
410 		yyerror("invalid cast -- %s\n", yytext);
411 	}
412 
413 <S_INITIAL>0[iI][0-1]+	|
414 <S_EXPR>0[iI][0-1]+	{
415 		/*
416 		 * Binary immediate value.
417 		 */
418 		yylval.l_immediate = mdb_strtonum(yytext + 2, 2);
419 		return (MDB_TOK_IMMEDIATE);
420 	}
421 
422 <S_INITIAL>0[oO][0-7]+	|
423 <S_EXPR>0[oO][0-7]+	{
424 		/*
425 		 * Octal immediate value.
426 		 */
427 		yylval.l_immediate = mdb_strtonum(yytext + 2, 8);
428 		return (MDB_TOK_IMMEDIATE);
429 	}
430 
431 <S_INITIAL>0[tT][0-9]+"."[0-9]+	|
432 <S_EXPR>0[tT][0-9]+"."[0-9]+	{
433 #ifdef _KMDB
434 		yyerror("floating point not supported\n");
435 #else
436 		/*
437 		 * Decimal floating point value.
438 		 */
439 		char *p, c;
440 		double d;
441 		int i;
442 
443 		if ((p = strsplit(yytext, '.')) == NULL)
444 			yyerror("internal scanning error -- expected '.'\n");
445 
446 		d = (double)mdb_strtonum(yytext + 2, 10);
447 
448 		for (i = 0; (c = *p++) != '\0'; i++)
449 			d = d * 10 + c - '0';
450 
451 		while (i-- != 0)
452 			d /= 10;
453 
454                 yylval.l_immediate = *((uintmax_t *)&d);
455 		return (MDB_TOK_IMMEDIATE);
456 #endif
457 	}
458 
459 <S_INITIAL>0[tT][0-9]+	|
460 <S_EXPR>0[tT][0-9]+	{
461 		/*
462 		 * Decimal immediate value.
463 		 */
464 		yylval.l_immediate = mdb_strtonum(yytext + 2, 10);
465 		return (MDB_TOK_IMMEDIATE);
466 	}
467 
468 <S_INITIAL>0[xX][0-9a-fA-F]+	|
469 <S_EXPR>0[xX][0-9a-fA-F]+	{
470 		/*
471 		 * Hexadecimal value.
472 		 */
473 		yylval.l_immediate = mdb_strtonum(yytext + 2, 16);
474 		return (MDB_TOK_IMMEDIATE);
475 	}
476 
477 <S_INITIAL>[0-9a-fA-F]+	|
478 <S_EXPR>[0-9a-fA-F]+	{
479 		GElf_Sym sym;
480 		/*
481 		 * Immediate values without an explicit base are converted
482 		 * using the default radix (user configurable).  However, if
483 		 * the token does *not* begin with a digit, it is also a
484 		 * potential symbol (e.g. "f") so we have to check that first.
485 		 */
486 		if (strchr("0123456789", yytext[0]) == NULL &&
487 		    mdb_tgt_lookup_by_name(mdb.m_target,
488 		    MDB_TGT_OBJ_EVERY, yytext, &sym, NULL) == 0)
489 			yylval.l_immediate = (uintmax_t)sym.st_value;
490 		else
491 			yylval.l_immediate = mdb_strtonum(yytext, mdb.m_radix);
492 		return (MDB_TOK_IMMEDIATE);
493 	}
494 
495 <S_INITIAL>{RGX_SYMBOL}	|
496 <S_EXPR>{RGX_SYMBOL}	{
497 		/*
498 		 * Symbol -- parser will look up in symbol table.
499 		 */
500 		yylval.l_string = strdup(yytext);
501 		return (MDB_TOK_SYMBOL);
502 	}
503 
504 ";"|\n	{
505 		/*
506 		 * End of command -- return to start state and return literal.
507 		 */
508 		BEGIN(S_INITIAL);
509 		return (yytext[0]);
510 	}
511 
512 [ \t]	;			/* Ignore whitespace */
513 
514 .	return (yytext[0]);	/* Return anything else */
515 
516 %%
517 
518 void
519 mdb_lex_debug(int i)
520 {
521 	yydebug = i;
522 }
523 
524 void
525 mdb_lex_reset(void)
526 {
527 	BEGIN(S_INITIAL);
528 }
529 
530 void
531 yydiscard(void)
532 {
533 	int c;
534 
535 	/*
536 	 * If stdin is a string, pipeline, or tty, throw away all our buffered
537 	 * data. Otherwise discard characters up to the next likely delimiter.
538 	 */
539 	if (mdb_iob_isastr(mdb.m_in) || mdb_iob_isatty(mdb.m_in) ||
540 	    mdb_iob_isapipe(mdb.m_in))
541 		mdb_iob_discard(mdb.m_in);
542 	else {
543 		while ((c = mdb_iob_getc(mdb.m_in)) != (int)EOF) {
544 			if (c == ';' || c == '\n')
545 				break;
546 		}
547 	}
548 
549 	BEGIN(S_INITIAL);
550 }
551 
552 static void
553 yyerror_reset(void)
554 {
555 	yydiscard();
556 	mdb_argvec_reset(&mdb.m_frame->f_argvec);
557 	longjmp(mdb.m_frame->f_pcb, MDB_ERR_PARSE);
558 }
559 
560 void
561 yyerror(const char *format, ...)
562 {
563 	va_list alist;
564 	char *s;
565 
566 	mdb_iob_printf(mdb.m_err, "%s: ", mdb.m_pname);
567 	va_start(alist, format);
568 	mdb_iob_vprintf(mdb.m_err, format, alist);
569 	va_end(alist);
570 
571 	if (strchr(format, '\n') == NULL) {
572 		if (!mdb_iob_isatty(mdb.m_in)) {
573 			mdb_iob_printf(mdb.m_err, " on line %d of %s",
574 			    yylineno, mdb_iob_name(mdb.m_in));
575 		}
576 
577 		s = strchr2esc(yytext, strlen(yytext));
578 		mdb_iob_printf(mdb.m_err, " near \"%s\"\n", s);
579 		strfree(s);
580 	}
581 
582 	yyerror_reset();
583 }
584 
585 void
586 yyperror(const char *format, ...)
587 {
588 	va_list alist;
589 
590 	va_start(alist, format);
591 	vwarn(format, alist);
592 	va_end(alist);
593 
594 	yyerror_reset();
595 }
596 
597 int
598 yywrap(void)
599 {
600 	mdb_dprintf(MDB_DBG_PARSER, "yywrap at line %d\n", yylineno);
601 	return (1); /* indicate that lex should return a zero token for EOF */
602 }
603 
604 /*PRINTFLIKE2*/
605 /*ARGSUSED*/
606 int
607 yyfprintf(FILE *stream, const char *format, ...)
608 {
609 	va_list alist;
610 
611 	va_start(alist, format);
612 	mdb_iob_vprintf(mdb.m_err, format, alist);
613 	va_end(alist);
614 	return (0);
615 }
616 
617 /*PRINTFLIKE1*/
618 int
619 yyprintf(const char *format, ...)
620 {
621 	va_list alist;
622 
623 	va_start(alist, format);
624 	mdb_iob_vprintf(mdb.m_err, format, alist);
625 	va_end(alist);
626 	return (0);
627 }
628 
629 static int
630 input(void)
631 {
632 	int c = mdb_iob_getc(mdb.m_in);
633 
634 	if (c == '\n')
635 		yylineno++;
636 
637 	return (c == EOF ? 0 : c);
638 }
639 
640 static void
641 unput(int c)
642 {
643 	if (c == '\n')
644 		yylineno--;
645 
646 	(void) mdb_iob_ungetc(mdb.m_in, c == 0 ? EOF : c);
647 }
648 
649 static void
650 output(int c)
651 {
652 	char ch = c;
653 	mdb_iob_nputs(mdb.m_out, &ch, sizeof (ch));
654 }
655 
656 static char *
657 string_nextquote(char *s, char q1, char q2)
658 {
659 	char c = 0;
660 
661 	do {
662 		if (c != '\\' && (*s == q1 || *s == q2))
663 			return (s);
664 	} while ((c = *s++) != '\0');
665 
666 	return (NULL);
667 }
668 
669 static void
670 string_unquote(char *s)
671 {
672 	char *o, *p, *q, c;
673 
674 	for (o = p = s; (p = string_nextquote(p, '\'', '"')) != NULL; o = p) {
675 		/*
676 		 * If the quote wasn't the first character, advance
677 		 * the destination buffer past what we skipped.
678 		 */
679 		if (p > o) {
680 			/* Using memmove to prevent possible overlap. */
681 			(void) memmove(s, o, p - o);
682 			s += p - o;
683 		}
684 
685 		c = *p;	/* Save the current quote */
686 
687 		/*
688 		 * Look ahead and find the matching quote.  If none is
689 		 * found, use yyerror to longjmp out of the lexer.
690 		 */
691 		if (c == '"')
692 			q = string_nextquote(p + 1, c, c);
693 		else
694 			q = strchr(p + 1, c);
695 
696 		if (q == NULL)
697 			yyerror("syntax error: %c unmatched", c);
698 
699 		/*
700 		 * If the string is non-empty, copy it to the destination
701 		 * and convert escape sequences if *p is double-quote.
702 		 */
703 		if (q > p + 1) {
704 			(void) memmove(s, p + 1, q - p - 1);
705 			if (c == '"') {
706                                 s[q - p - 1] = '\0';
707 				s += stresc2chr(s);
708 			} else
709 				s += q - p - 1;
710 		}
711 
712 		p = q + 1; /* Advance p past matching quote */
713 	}
714 
715 	(void) memmove(s, o, strlen(o) + 1);
716 }
717 
718 /*
719  * Unfortunately, lex and yacc produces code that is inherently global.  They do
720  * not provide routines to save and restore state, instead relying on global
721  * variables.  There is one single lex state, so that if a frame switch then
722  * tries to perform any evaluation, the old values are corrupted.  This
723  * structure and corresponding function provide a means of preserving lex state
724  * across frame switches.  Note that this is tied to the lex implementation, so
725  * if the lex compiler is changed or upgraded to a different format, then this
726  * may need to be altered.  This is unavoidable due to the implementation of lex
727  * and yacc. This is essentially a collection of all the global variables
728  * defined by the lex code, excluding those that do not change through the
729  * course of yylex() and yyparse().
730  */
731 extern struct yysvf *yylstate[], **yylsp, **yyolsp; extern int yyprevious;
732 extern int *yyfnd;
733 
734 extern YYSTYPE *yypv;
735 extern int *yyps;
736 extern int yytmp;
737 extern int yystate;
738 extern int yynerrs;
739 extern int yyerrflag;
740 extern int yychar;
741 extern YYSTYPE yylval;
742 extern YYSTYPE yyval;
743 extern int *yys;
744 extern YYSTYPE *yyv;
745 
746 typedef struct mdb_lex_state {
747 	/* Variables needed by yylex */
748 	int	yyleng;
749 	char	yytext[YYLMAX];
750 	int	yymorfg;
751 	int	yylineno;
752 	void	*yyestate;
753 	void	*yylstate[BUFSIZ];
754 	void	*yylsp;
755 	void	*yyolsp;
756 	int	*yyfnd;
757 	int	yyprevious;
758 	void	*yybgin;
759 	/* Variables needed by yyparse */
760 	void 	*yypv;
761 	int	*yyps;
762 	int	yytmp;
763 	int	yystate;
764 	int	yynerrs;
765 	int	yyerrflag;
766 	int	yychar;
767 	YYSTYPE	yylval;
768 	YYSTYPE	yyval;
769 	int	yys[YYMAXDEPTH];
770 	YYSTYPE	yyv[YYMAXDEPTH];
771 } mdb_lex_state_t;
772 
773 void
774 mdb_lex_state_save(mdb_lex_state_t *s)
775 {
776 	ASSERT(s != NULL);
777 
778 	s->yyleng = yyleng;
779 	s->yymorfg = yymorfg;
780 	s->yylineno = yylineno;
781 	s->yyestate = yyestate;
782 	bcopy(yylstate, s->yylstate, YYLMAX * sizeof (void *));
783 	s->yylsp = yylsp;
784 	s->yyolsp = yyolsp;
785 	s->yyfnd = yyfnd;
786 	s->yyprevious = yyprevious;
787 	s->yybgin = yybgin;
788 
789 	s->yypv = yypv;
790 	s->yyps = yyps;
791 	s->yystate = yystate;
792 	s->yytmp = yytmp;
793 	s->yynerrs = yynerrs;
794 	s->yyerrflag = yyerrflag;
795 	s->yychar = yychar;
796 	s->yylval = yylval;
797 	s->yyval = yyval;
798 }
799 
800 void
801 mdb_lex_state_restore(mdb_lex_state_t *s)
802 {
803 	ASSERT(s != NULL);
804 
805 	yyleng = s->yyleng;
806 	yytext = s->yytext;
807 	yymorfg = s->yymorfg;
808 	yylineno = s->yylineno;
809 	yyestate = s->yyestate;
810 	bcopy(s->yylstate, yylstate, YYLMAX * sizeof (void *));
811 	yylsp = s->yylsp;
812 	yyolsp = s->yyolsp;
813 	yyfnd = s->yyfnd;
814 	yyprevious = s->yyprevious;
815 	yybgin = s->yybgin;
816 
817 	yypv = s->yypv;
818 	yyps = s->yyps;
819 	yystate = s->yystate;
820 	yytmp = s->yytmp;
821 	yynerrs = s->yynerrs;
822 	yyerrflag = s->yyerrflag;
823 	yychar = s->yychar;
824 	yylval = s->yylval;
825 	yyval = s->yyval;
826 	yys = s->yys;
827 	yyv = s->yyv;
828 }
829 
830 /*
831  * Create and initialize the lex/yacc-specific state associated with a frame
832  * structure.  We set all fields to known safe values so that
833  * mdb_lex_state_restore() can be used safely before mdb_lex_state_save().
834  */
835 void
836 mdb_lex_state_create(mdb_frame_t *f)
837 {
838 	f->f_lstate = mdb_alloc(sizeof (mdb_lex_state_t), UM_SLEEP);
839 
840 	yyleng = 0;
841 	yymorfg = 0;
842 	/* yytext is fine with garbage in it */
843 	yytext = f->f_lstate->yytext;
844 	yylineno = 1;
845 	yyestate = NULL;
846 	bzero(yylstate, YYLMAX * sizeof (void *));
847 	yylsp = NULL;
848 	yyolsp = NULL;
849 	yyfnd = 0;
850 	yyprevious = YYNEWLINE;
851 	yys = f->f_lstate->yys;
852 	yyv = f->f_lstate->yyv;
853 	mdb_argvec_create(&f->f_argvec);
854 	f->f_oldstate = 0;
855 	mdb_lex_reset(); /* Responsible for setting yybgin */
856 }
857 
858 void
859 mdb_lex_state_destroy(mdb_frame_t *f)
860 {
861 	mdb_free(f->f_lstate, sizeof (mdb_lex_state_t));
862 	f->f_lstate = NULL;
863 	mdb_argvec_destroy(&f->f_argvec);
864 }
865