1 /*
2  * Copyright (c) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
3  *	2010, 2015
4  *	Tama Communications Corporation
5  *
6  * This file is part of GNU GLOBAL.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #ifdef HAVE_STRING_H
26 #include <string.h>
27 #else
28 #include <strings.h>
29 #endif
30 
31 #include "internal.h"
32 #include "die.h"
33 #include "strbuf.h"
34 #include "strlimcpy.h"
35 #include "token.h"
36 #include "c_res.h"
37 
38 static void C_family(const struct parser_param *, int);
39 static void process_attribute(const struct parser_param *);
40 static int function_definition(const struct parser_param *, char *);
41 static void condition_macro(const struct parser_param *, int);
42 static int enumerator_list(const struct parser_param *);
43 
44 #define IS_TYPE_QUALIFIER(c)	((c) == C_CONST || (c) == C_RESTRICT || (c) == C_VOLATILE)
45 
46 #define DECLARATIONS    0
47 #define RULES           1
48 #define PROGRAMS        2
49 
50 #define TYPE_C		0
51 #define TYPE_LEX	1
52 #define TYPE_YACC	2
53 
54 #define MAXPIFSTACK	100
55 
56 /*
57  * #ifdef stack.
58  */
59 static struct {
60 	short start;		/* level when '#if' block started */
61 	short end;		/* level when '#if' block end */
62 	short if0only;		/* '#if 0' or notdef only */
63 } stack[MAXPIFSTACK], *cur;
64 static int piflevel;		/* condition macro level */
65 static int level;		/* brace level */
66 static int externclevel;	/* 'extern "C"' block level */
67 
68 /**
69  * yacc: read yacc file and pickup tag entries.
70  */
71 void
yacc(const struct parser_param * param)72 yacc(const struct parser_param *param)
73 {
74 	C_family(param, TYPE_YACC);
75 }
76 /**
77  * C: read C file and pickup tag entries.
78  */
79 void
C(const struct parser_param * param)80 C(const struct parser_param *param)
81 {
82 	C_family(param, TYPE_C);
83 }
84 /**
85  *	@param[in]	param	source file
86  *	@param[in]	type	TYPE_C, TYPE_YACC, TYPE_LEX
87  */
88 static void
C_family(const struct parser_param * param,int type)89 C_family(const struct parser_param *param, int type)
90 {
91 	int c, cc;
92 	int savelevel;
93 	int startmacro, startsharp;
94 	const char *interested = "{}=;";
95 	STRBUF *sb = strbuf_open(0);
96 	/*
97 	 * yacc file format is like the following.
98 	 *
99 	 * declarations
100 	 * %%
101 	 * rules
102 	 * %%
103 	 * programs
104 	 *
105 	 */
106 	int yaccstatus = (type == TYPE_YACC) ? DECLARATIONS : PROGRAMS;
107 	int inC = (type == TYPE_YACC) ? 0 : 1;	/* 1 while C source */
108 
109 	level = piflevel = externclevel = 0;
110 	savelevel = -1;
111 	startmacro = startsharp = 0;
112 
113 	if (!opentoken(param->file))
114 		die("'%s' cannot open.", param->file);
115 	cmode = 1;			/* allow token like '#xxx' */
116 	crflag = 1;			/* require '\n' as a token */
117 	if (type == TYPE_YACC)
118 		ymode = 1;		/* allow token like '%xxx' */
119 
120 	while ((cc = nexttoken(interested, c_reserved_word)) != EOF) {
121 		switch (cc) {
122 		case SYMBOL:		/* symbol	*/
123 			if (inC && peekc(0) == '('/* ) */) {
124 				if (param->isnotfunction(token)) {
125 					PUT(PARSER_REF_SYM, token, lineno, sp);
126 				} else if (level > 0 || startmacro) {
127 					PUT(PARSER_REF_SYM, token, lineno, sp);
128 				} else if (level == 0 && !startmacro && !startsharp) {
129 					char arg1[MAXTOKEN], savetok[MAXTOKEN], *saveline;
130 					int savelineno = lineno;
131 
132 					strlimcpy(savetok, token, sizeof(savetok));
133 					strbuf_reset(sb);
134 					strbuf_puts(sb, sp);
135 					saveline = strbuf_value(sb);
136 					arg1[0] = '\0';
137 					/*
138 					 * Guile function entry using guile-snarf is like follows:
139 					 *
140 					 * SCM_DEFINE (scm_list, "list", 0, 0, 1,
141 					 *           (SCM objs),
142 					 *            "Return a list containing OBJS, the arguments to `list'.")
143 					 * #define FUNC_NAME s_scm_list
144 					 * {
145 					 *   return objs;
146 					 * }
147 					 * #undef FUNC_NAME
148 					 *
149 					 * We should assume the first argument as a function name instead of 'SCM_DEFINE'.
150 					 */
151 					if (function_definition(param, arg1)) {
152 						if (!strcmp(savetok, "SCM_DEFINE") && *arg1)
153 							strlimcpy(savetok, arg1, sizeof(savetok));
154 						PUT(PARSER_DEF, savetok, savelineno, saveline);
155 					} else {
156 						PUT(PARSER_REF_SYM, savetok, savelineno, saveline);
157 					}
158 				}
159 			} else {
160 				PUT(PARSER_REF_SYM, token, lineno, sp);
161 			}
162 			break;
163 		case '{':  /* } */
164 			DBG_PRINT(level, "{"); /* } */
165 			if (yaccstatus == RULES && level == 0)
166 				inC = 1;
167 			++level;
168 			if ((param->flags & PARSER_BEGIN_BLOCK) && atfirst) {
169 				if ((param->flags & PARSER_WARNING) && level != 1)
170 					warning("forced level 1 block start by '{' at column 0 [+%d %s].", lineno, curfile); /* } */
171 				level = 1;
172 			}
173 			break;
174 			/* { */
175 		case '}':
176 			if (--level < 0) {
177 				if (externclevel > 0)
178 					externclevel--;
179 				else if (param->flags & PARSER_WARNING)
180 					warning("missing left '{' [+%d %s].", lineno, curfile); /* } */
181 				level = 0;
182 			}
183 			if ((param->flags & PARSER_END_BLOCK) && atfirst) {
184 				if ((param->flags & PARSER_WARNING) && level != 0) /* { */
185 					warning("forced level 0 block end by '}' at column 0 [+%d %s].", lineno, curfile);
186 				level = 0;
187 			}
188 			if (yaccstatus == RULES && level == 0)
189 				inC = 0;
190 			/* { */
191 			DBG_PRINT(level, "}");
192 			break;
193 		case '\n':
194 			if (startmacro && level != savelevel) {
195 				if (param->flags & PARSER_WARNING)
196 					warning("different level before and after #define macro. reseted. [+%d %s].", lineno, curfile);
197 				level = savelevel;
198 			}
199 			startmacro = startsharp = 0;
200 			break;
201 		case YACC_SEP:		/* %% */
202 			if (level != 0) {
203 				if (param->flags & PARSER_WARNING)
204 					warning("forced level 0 block end by '%%' [+%d %s].", lineno, curfile);
205 				level = 0;
206 			}
207 			if (yaccstatus == DECLARATIONS) {
208 				PUT(PARSER_DEF, "yyparse", lineno, sp);
209 				yaccstatus = RULES;
210 			} else if (yaccstatus == RULES)
211 				yaccstatus = PROGRAMS;
212 			inC = (yaccstatus == PROGRAMS) ? 1 : 0;
213 			break;
214 		case YACC_BEGIN:	/* %{ */
215 			if (level != 0) {
216 				if (param->flags & PARSER_WARNING)
217 					warning("forced level 0 block end by '%%{' [+%d %s].", lineno, curfile);
218 				level = 0;
219 			}
220 			if (inC == 1 && (param->flags & PARSER_WARNING))
221 				warning("'%%{' appeared in C mode. [+%d %s].", lineno, curfile);
222 			inC = 1;
223 			break;
224 		case YACC_END:		/* %} */
225 			if (level != 0) {
226 				if (param->flags & PARSER_WARNING)
227 					warning("forced level 0 block end by '%%}' [+%d %s].", lineno, curfile);
228 				level = 0;
229 			}
230 			if (inC == 0 && (param->flags & PARSER_WARNING))
231 				warning("'%%}' appeared in Yacc mode. [+%d %s].", lineno, curfile);
232 			inC = 0;
233 			break;
234 		case YACC_UNION:	/* %union {...} */
235 			if (yaccstatus == DECLARATIONS)
236 				PUT(PARSER_DEF, "YYSTYPE", lineno, sp);
237 			break;
238 		/*
239 		 * #xxx
240 		 */
241 		case SHARP_DEFINE:
242 		case SHARP_UNDEF:
243 			startmacro = 1;
244 			savelevel = level;
245 			if ((c = nexttoken(interested, c_reserved_word)) != SYMBOL) {
246 				pushbacktoken();
247 				break;
248 			}
249 			if (peekc(1) == '('/* ) */) {
250 				PUT(PARSER_DEF, token, lineno, sp);
251 				while ((c = nexttoken("()", c_reserved_word)) != EOF && c != '\n' && c != /* ( */ ')')
252 					if (c == SYMBOL)
253 						PUT(PARSER_REF_SYM, token, lineno, sp);
254 				if (c == '\n')
255 					pushbacktoken();
256 			} else {
257 				PUT(PARSER_DEF, token, lineno, sp);
258 			}
259 			break;
260 		case SHARP_IMPORT:
261 		case SHARP_INCLUDE:
262 		case SHARP_INCLUDE_NEXT:
263 		case SHARP_ERROR:
264 		case SHARP_LINE:
265 		case SHARP_PRAGMA:
266 		case SHARP_WARNING:
267 		case SHARP_IDENT:
268 		case SHARP_SCCS:
269 			while ((c = nexttoken(interested, c_reserved_word)) != EOF && c != '\n')
270 				;
271 			break;
272 		case SHARP_IFDEF:
273 		case SHARP_IFNDEF:
274 		case SHARP_IF:
275 		case SHARP_ELIF:
276 		case SHARP_ELSE:
277 		case SHARP_ENDIF:
278 			condition_macro(param, cc);
279 			break;
280 		case SHARP_SHARP:		/* ## */
281 			(void)nexttoken(interested, c_reserved_word);
282 			break;
283 		case C_EXTERN: /* for 'extern "C"/"C++"' */
284 			if (peekc(0) != '"') /* " */
285 				continue; /* If does not start with '"', continue. */
286 			while ((c = nexttoken(interested, c_reserved_word)) == '\n')
287 				;
288 			/*
289 			 * 'extern "C"/"C++"' block is a kind of namespace block.
290 			 * (It doesn't have any influence on level.)
291 			 */
292 			if (c == '{') /* } */
293 				externclevel++;
294 			else
295 				pushbacktoken();
296 			break;
297 		case C_STRUCT:
298 		case C_ENUM:
299 		case C_UNION:
300 			while ((c = nexttoken(interested, c_reserved_word)) == C___ATTRIBUTE__)
301 				process_attribute(param);
302 			while (c == '\n')
303 				c = nexttoken(interested, c_reserved_word);
304 			if (c == SYMBOL) {
305 				if (peekc(0) == '{') /* } */ {
306 					PUT(PARSER_DEF, token, lineno, sp);
307 				} else {
308 					PUT(PARSER_REF_SYM, token, lineno, sp);
309 				}
310 				c = nexttoken(interested, c_reserved_word);
311 			}
312 			while (c == '\n')
313 				c = nexttoken(interested, c_reserved_word);
314 			if (c == '{' /* } */ && cc == C_ENUM) {
315 				enumerator_list(param);
316 			} else {
317 				pushbacktoken();
318 			}
319 			break;
320 		/* control statement check */
321 		case C_BREAK:
322 		case C_CASE:
323 		case C_CONTINUE:
324 		case C_DEFAULT:
325 		case C_DO:
326 		case C_ELSE:
327 		case C_FOR:
328 		case C_GOTO:
329 		case C_IF:
330 		case C_RETURN:
331 		case C_SWITCH:
332 		case C_WHILE:
333 			if ((param->flags & PARSER_WARNING) && !startmacro && level == 0)
334 				warning("Out of function. %8s [+%d %s]", token, lineno, curfile);
335 			break;
336 		case C_TYPEDEF:
337 			{
338 				/*
339 				 * This parser is too complex to maintain.
340 				 * We should rewrite the whole.
341 				 */
342 				char savetok[MAXTOKEN];
343 				int savelineno = 0;
344 				int typedef_savelevel = level;
345 
346 				savetok[0] = 0;
347 
348 				/* skip type qualifiers */
349 				do {
350 					c = nexttoken("{}(),;", c_reserved_word);
351 				} while (IS_TYPE_QUALIFIER(c) || c == '\n');
352 
353 				if ((param->flags & PARSER_WARNING) && c == EOF) {
354 					warning("unexpected eof. [+%d %s]", lineno, curfile);
355 					break;
356 				} else if (c == C_ENUM || c == C_STRUCT || c == C_UNION) {
357 					char *interest_enum = "{},;";
358 					int c_ = c;
359 
360 					while ((c = nexttoken(interest_enum, c_reserved_word)) == C___ATTRIBUTE__)
361 						process_attribute(param);
362 					while (c == '\n')
363 						c = nexttoken(interest_enum, c_reserved_word);
364 					/* read tag name if exist */
365 					if (c == SYMBOL) {
366 						if (peekc(0) == '{') /* } */ {
367 							PUT(PARSER_DEF, token, lineno, sp);
368 						} else {
369 							PUT(PARSER_REF_SYM, token, lineno, sp);
370 						}
371 						c = nexttoken(interest_enum, c_reserved_word);
372 					}
373 					while (c == '\n')
374 						c = nexttoken(interest_enum, c_reserved_word);
375 					if (c_ == C_ENUM) {
376 						if (c == '{') /* } */
377 							c = enumerator_list(param);
378 						else
379 							pushbacktoken();
380 					} else {
381 						for (; c != EOF; c = nexttoken(interest_enum, c_reserved_word)) {
382 							switch (c) {
383 							case SHARP_IFDEF:
384 							case SHARP_IFNDEF:
385 							case SHARP_IF:
386 							case SHARP_ELIF:
387 							case SHARP_ELSE:
388 							case SHARP_ENDIF:
389 								condition_macro(param, c);
390 								continue;
391 							default:
392 								break;
393 							}
394 							if (c == ';' && level == typedef_savelevel) {
395 								if (savetok[0]) {
396 									PUT(PARSER_DEF, savetok, savelineno, sp);
397 									savetok[0] = 0;
398 								}
399 								break;
400 							} else if (c == '{')
401 								level++;
402 							else if (c == '}') {
403 								savetok[0] = 0;
404 								if (--level == typedef_savelevel)
405 									break;
406 							} else if (c == SYMBOL) {
407 								if (level > typedef_savelevel)
408 									PUT(PARSER_REF_SYM, token, lineno, sp);
409 								/* save lastest token */
410 								strlimcpy(savetok, token, sizeof(savetok));
411 								savelineno = lineno;
412 							}
413 						}
414 						if (c == ';')
415 							break;
416 					}
417 					if ((param->flags & PARSER_WARNING) && c == EOF) {
418 						warning("unexpected eof. [+%d %s]", lineno, curfile);
419 						break;
420 					}
421 				} else if (c == SYMBOL) {
422 					PUT(PARSER_REF_SYM, token, lineno, sp);
423 				}
424 				savetok[0] = 0;
425 				while ((c = nexttoken("(),;", c_reserved_word)) != EOF) {
426 					switch (c) {
427 					case SHARP_IFDEF:
428 					case SHARP_IFNDEF:
429 					case SHARP_IF:
430 					case SHARP_ELIF:
431 					case SHARP_ELSE:
432 					case SHARP_ENDIF:
433 						condition_macro(param, c);
434 						continue;
435 					default:
436 						break;
437 					}
438 					if (c == '(')
439 						level++;
440 					else if (c == ')')
441 						level--;
442 					else if (c == SYMBOL) {
443 						if (level > typedef_savelevel) {
444 							PUT(PARSER_REF_SYM, token, lineno, sp);
445 						} else {
446 							/* put latest token if any */
447 							if (savetok[0]) {
448 								PUT(PARSER_REF_SYM, savetok, savelineno, sp);
449 							}
450 							/* save lastest token */
451 							strlimcpy(savetok, token, sizeof(savetok));
452 							savelineno = lineno;
453 						}
454 					} else if (c == ',' || c == ';') {
455 						if (savetok[0]) {
456 							PUT(PARSER_DEF, savetok, lineno, sp);
457 							savetok[0] = 0;
458 						}
459 					}
460 					if (level == typedef_savelevel && c == ';')
461 						break;
462 				}
463 				if (param->flags & PARSER_WARNING) {
464 					if (c == EOF)
465 						warning("unexpected eof. [+%d %s]", lineno, curfile);
466 					else if (level != typedef_savelevel)
467 						warning("unmatched () block. (last at level %d.)[+%d %s]", level, lineno, curfile);
468 				}
469 			}
470 			break;
471 		case C___ATTRIBUTE__:
472 			process_attribute(param);
473 			break;
474 		default:
475 			break;
476 		}
477 	}
478 	strbuf_close(sb);
479 	if (param->flags & PARSER_WARNING) {
480 		if (level != 0)
481 			warning("unmatched {} block. (last at level %d.)[+%d %s]", level, lineno, curfile);
482 		if (piflevel != 0)
483 			warning("unmatched #if block. (last at level %d.)[+%d %s]", piflevel, lineno, curfile);
484 	}
485 	closetoken();
486 }
487 /**
488  * process_attribute: skip attributes in '__attribute__((...))'.
489  */
490 static void
process_attribute(const struct parser_param * param)491 process_attribute(const struct parser_param *param)
492 {
493 	int brace = 0;
494 	int c;
495 	/*
496 	 * Skip '...' in __attribute__((...))
497 	 * but pick up symbols in it.
498 	 */
499 	while ((c = nexttoken("()", c_reserved_word)) != EOF) {
500 		if (c == '(')
501 			brace++;
502 		else if (c == ')')
503 			brace--;
504 		else if (c == SYMBOL) {
505 			PUT(PARSER_REF_SYM, token, lineno, sp);
506 		}
507 		if (brace == 0)
508 			break;
509 	}
510 }
511 /**
512  * function_definition: return if function definition or not.
513  *
514  *	@param	param
515  *	@param[out]	arg1	the first argument
516  *	@return	target type
517  */
518 static int
function_definition(const struct parser_param * param,char arg1[MAXTOKEN])519 function_definition(const struct parser_param *param, char arg1[MAXTOKEN])
520 {
521 	int c;
522 	int brace_level, isdefine;
523 	int accept_arg1 = 0;
524 
525 	brace_level = isdefine = 0;
526 	while ((c = nexttoken("()", c_reserved_word)) != EOF) {
527 		switch (c) {
528 		case SHARP_IFDEF:
529 		case SHARP_IFNDEF:
530 		case SHARP_IF:
531 		case SHARP_ELIF:
532 		case SHARP_ELSE:
533 		case SHARP_ENDIF:
534 			condition_macro(param, c);
535 			continue;
536 		default:
537 			break;
538 		}
539 		if (c == '('/* ) */)
540 			brace_level++;
541 		else if (c == /* ( */')') {
542 			if (--brace_level == 0)
543 				break;
544 		}
545 		/* pick up symbol */
546 		if (c == SYMBOL) {
547 			if (accept_arg1 == 0) {
548 				accept_arg1 = 1;
549 				strlimcpy(arg1, token, MAXTOKEN);
550 			}
551 			PUT(PARSER_REF_SYM, token, lineno, sp);
552 		}
553 	}
554 	if (c == EOF)
555 		return 0;
556 	brace_level = 0;
557 	while ((c = nexttoken(",;[](){}=", c_reserved_word)) != EOF) {
558 		switch (c) {
559 		case SHARP_IFDEF:
560 		case SHARP_IFNDEF:
561 		case SHARP_IF:
562 		case SHARP_ELIF:
563 		case SHARP_ELSE:
564 		case SHARP_ENDIF:
565 			condition_macro(param, c);
566 			continue;
567 		case C___ATTRIBUTE__:
568 			process_attribute(param);
569 			continue;
570 		case SHARP_DEFINE:
571 			pushbacktoken();
572 			return 0;
573 		default:
574 			break;
575 		}
576 		if (c == '('/* ) */ || c == '[')
577 			brace_level++;
578 		else if (c == /* ( */')' || c == ']')
579 			brace_level--;
580 		else if (brace_level == 0
581 		    && ((c == SYMBOL && strcmp(token, "__THROW")) || IS_RESERVED_WORD(c)))
582 			isdefine = 1;
583 		else if (c == ';' || c == ',') {
584 			if (!isdefine)
585 				break;
586 		} else if (c == '{' /* } */) {
587 			pushbacktoken();
588 			return 1;
589 		} else if (c == /* { */'}')
590 			break;
591 		else if (c == '=')
592 			break;
593 
594 		/* pick up symbol */
595 		if (c == SYMBOL)
596 			PUT(PARSER_REF_SYM, token, lineno, sp);
597 	}
598 	return 0;
599 }
600 
601 /**
602  * condition_macro:
603  *
604  *	@param	param
605  *	@param[in]	cc	token
606  */
607 static void
condition_macro(const struct parser_param * param,int cc)608 condition_macro(const struct parser_param *param, int cc)
609 {
610 	cur = &stack[piflevel];
611 	if (cc == SHARP_IFDEF || cc == SHARP_IFNDEF || cc == SHARP_IF) {
612 		DBG_PRINT(piflevel, "#if");
613 		if (++piflevel >= MAXPIFSTACK)
614 			die("#if stack over flow. [%s]", curfile);
615 		++cur;
616 		cur->start = level;
617 		cur->end = -1;
618 		cur->if0only = 0;
619 		if (peekc(0) == '0')
620 			cur->if0only = 1;
621 		else if ((cc = nexttoken(NULL, c_reserved_word)) == SYMBOL && !strcmp(token, "notdef"))
622 			cur->if0only = 1;
623 		else
624 			pushbacktoken();
625 	} else if (cc == SHARP_ELIF || cc == SHARP_ELSE) {
626 		DBG_PRINT(piflevel - 1, "#else");
627 		if (cur->end == -1)
628 			cur->end = level;
629 		else if (cur->end != level && (param->flags & PARSER_WARNING))
630 			warning("uneven level. [+%d %s]", lineno, curfile);
631 		level = cur->start;
632 		cur->if0only = 0;
633 	} else if (cc == SHARP_ENDIF) {
634 		int minus = 0;
635 
636 		--piflevel;
637 		if (piflevel < 0) {
638 			minus = 1;
639 			piflevel = 0;
640 		}
641 		DBG_PRINT(piflevel, "#endif");
642 		if (minus) {
643 			if (param->flags & PARSER_WARNING)
644 				warning("unmatched #if block. reseted. [+%d %s]", lineno, curfile);
645 		} else {
646 			if (cur->if0only)
647 				level = cur->start;
648 			else if (cur->end != -1) {
649 				if (cur->end != level && (param->flags & PARSER_WARNING))
650 					warning("uneven level. [+%d %s]", lineno, curfile);
651 				level = cur->end;
652 			}
653 		}
654 	}
655 	while ((cc = nexttoken(NULL, c_reserved_word)) != EOF && cc != '\n') {
656 		if (cc == SYMBOL && strcmp(token, "defined") != 0)
657 			PUT(PARSER_REF_SYM, token, lineno, sp);
658 	}
659 }
660 
661 /**
662  * enumerator_list: process "symbol (= expression), ... "}
663  */
664 static int
enumerator_list(const struct parser_param * param)665 enumerator_list(const struct parser_param *param)
666 {
667 	int savelevel = level;
668 	int in_expression = 0;
669 	int c = '{';
670 
671 	for (; c != EOF; c = nexttoken("{}(),=", c_reserved_word)) {
672 		switch (c) {
673 		case SHARP_IFDEF:
674 		case SHARP_IFNDEF:
675 		case SHARP_IF:
676 		case SHARP_ELIF:
677 		case SHARP_ELSE:
678 		case SHARP_ENDIF:
679 			condition_macro(param, c);
680 			break;
681 		case SYMBOL:
682 			if (in_expression)
683 				PUT(PARSER_REF_SYM, token, lineno, sp);
684 			else
685 				PUT(PARSER_DEF, token, lineno, sp);
686 			break;
687 		case '{':
688 		case '(':
689 			level++;
690 			break;
691 		case '}':
692 		case ')':
693 			if (--level == savelevel)
694 				return c;
695 			break;
696 		case ',':
697 			if (level == savelevel + 1)
698 				in_expression = 0;
699 			break;
700 		case '=':
701 			in_expression = 1;
702 			break;
703 		default:
704 			break;
705 		}
706 	}
707 
708 	return c;
709 }
710