1 #include	"recipe.h"
2 #include	"lexer.h"
3 #include	"token.h"
4 #include	"funcs.h"
5 
6 static const char rcsid[]="$Id: recipeparse.C,v 1.11 2010/06/01 00:13:28 mrsam Exp $";
7 
ParseRecipe(Lexer & l)8 int Recipe::ParseRecipe(Lexer &l)
9 {
10 	lex= &l;
11 	lex->token(cur_tok);
12 	try
13 	{
14 		topNode=ParseStatementList();
15 	}
16 	catch (const char *p)
17 	{
18 		l.errmsg(p);
19 		return (-1);
20 	}
21 #if NEED_NONCONST_EXCEPTIONS
22 	catch (char *p)
23 	{
24 		l.errmsg(p);
25 		return (-1);
26 	}
27 #endif
28 	if (cur_tok.Type() != cur_tok.eof)
29 	{
30 		l.errmsg("Syntax error.");
31 		return (-1);
32 	}
33 	return (0);
34 }
35 
ParseStatementList()36 RecipeNode *Recipe::ParseStatementList()
37 {
38 RecipeNode *n=alloc(RecipeNode::statementlist);
39 Token::tokentype type;
40 
41 	while ( (type=cur_tok.Type()) != cur_tok.rbrace && type != cur_tok.eof)
42 	{
43 		if (type == cur_tok.semicolon)
44 		{
45 			lex->token(cur_tok);
46 			continue;
47 		}
48 
49 	RecipeNode *o=ParseStatement();
50 
51 		n->AppendSibling(o);
52 	}
53 	return (n);
54 }
55 
ParseStatement()56 RecipeNode *Recipe::ParseStatement()
57 {
58 RecipeNode *n, *o;
59 
60 	switch (cur_tok.Type())	{
61 	case Token::tokenif:
62 		lex->token(cur_tok);
63 		if (cur_tok.Type() != Token::lparen)
64 			throw "Syntax error after if";
65 
66 		lex->token(cur_tok);
67 
68 		n=alloc(RecipeNode::ifelse);
69 		o=ParseExpr();
70 
71 		n->AppendSibling(o);
72 
73 		if (cur_tok.Type() != Token::rparen)
74 			throw "Missing )";
75 
76 		lex->token(cur_tok);
77 		if (cur_tok.Type() != Token::semicolon)	// Newline/semicolon
78 			throw "Syntax error after )";
79 
80 		lex->token(cur_tok);
81 		n->AppendSibling(ParseSubStatement());
82 		if (cur_tok.Type() == Token::tokenelse)
83 		{
84 			lex->token(cur_tok);
85 			if (cur_tok.Type() != Token::semicolon)	// Newline/semicolon
86 				throw "Syntax error after else";
87 
88 			lex->token(cur_tok);
89 			n->AppendSibling(ParseSubStatement());
90 		}
91 		else if (cur_tok.Type() == Token::tokenelsif)
92 		{
93 			cur_tok.Type(Token::tokenif);
94 			n->AppendSibling(ParseStatement());
95 		}
96 		return (n);
97 	case Token::tokenwhile:
98 		lex->token(cur_tok);
99 		if (cur_tok.Type() != Token::lparen)
100 			throw "Syntax error after while";
101 
102 		lex->token(cur_tok);
103 
104 		n=alloc(RecipeNode::whileloop);
105 		o=ParseExpr();
106 		n->AppendSibling(o);
107 
108 		if (cur_tok.Type() != Token::rparen)
109 			throw "Missing )";
110 
111 		lex->token(cur_tok);
112 		if (cur_tok.Type() != Token::semicolon)	// Newline/semicolon
113 			throw "Syntax error after else";
114 
115 		lex->token(cur_tok);
116 		n->AppendSibling(ParseSubStatement());
117 		return (n);
118 	case Token::lbrace:
119 		lex->token(cur_tok);
120 		n=ParseStatementList();
121 		if (cur_tok.Type() != Token::rbrace)
122 			throw "Missing }";
123 
124 		lex->token(cur_tok);
125 		if (cur_tok.Type() != Token::semicolon)
126 		{
127 			throw "Syntax error after }";
128 		}
129 		lex->token(cur_tok);
130 		return (n);
131 	case Token::tokento:
132 		lex->token(cur_tok);
133 		n=alloc(RecipeNode::deliver);
134 		o=ParseExpr();
135 		n->AppendSibling(o);
136 		if (cur_tok.Type() != Token::semicolon)
137 			throw "Syntax error.";
138 
139 		lex->token(cur_tok);
140 		return (n);
141 	case Token::tokencc:
142 		lex->token(cur_tok);
143 		n=alloc(RecipeNode::delivercc);
144 		o=ParseExpr();
145 		n->AppendSibling(o);
146 		if (cur_tok.Type() != Token::semicolon)
147 			throw "Syntax error.";
148 
149 		lex->token(cur_tok);
150 		return (n);
151 	case Token::exception:
152 		lex->token(cur_tok);
153 		if (cur_tok.Type() != Token::lbrace)
154 			throw "Syntax error.";
155 
156 		n=alloc(RecipeNode::exception);
157 		o=ParseStatement();
158 		n->AppendSibling(o);
159 		return (n);
160 	case Token::echo:
161 		lex->token(cur_tok);
162 		n=alloc(RecipeNode::echo);
163 		n->AppendSibling( ParseExpr());
164 		if (cur_tok.Type() != Token::semicolon)
165 			throw "Syntax error.";
166 		lex->token(cur_tok);
167 		return (n);
168 	case Token::tokenxfilter:
169 		lex->token(cur_tok);
170 		n=alloc(RecipeNode::xfilter);
171 		n->AppendSibling( ParseExpr());
172 		if (cur_tok.Type() != Token::semicolon)
173 			throw "Syntax error.";
174 		lex->token(cur_tok);
175 		return (n);
176 	case Token::dotlock:
177 		lex->token(cur_tok);
178 		n=alloc(RecipeNode::dotlock);
179 		n->AppendSibling( ParseExpr());
180 		if (cur_tok.Type() != Token::lbrace)
181 			throw "Syntax error.";
182 		n->AppendSibling( ParseStatement() );
183 		return (n);
184 	case Token::flock:
185 		lex->token(cur_tok);
186 		n=alloc(RecipeNode::flock);
187 		n->AppendSibling( ParseExpr());
188 		if (cur_tok.Type() != Token::lbrace)
189 			throw "Syntax error.";
190 		n->AppendSibling( ParseStatement() );
191 		return (n);
192 	case Token::logfile:
193 		lex->token(cur_tok);
194 		n=alloc(RecipeNode::logfile);
195 		n->AppendSibling( ParseExpr());
196 		if (cur_tok.Type() != Token::semicolon)
197 			throw "Syntax error.";
198 		lex->token(cur_tok);
199 		return (n);
200 	case Token::log:
201 		lex->token(cur_tok);
202 		n=alloc(RecipeNode::log);
203 		n->AppendSibling( ParseExpr());
204 		if (cur_tok.Type() != Token::semicolon)
205 			throw "Syntax error.";
206 		lex->token(cur_tok);
207 		return (n);
208 	case Token::include:
209 		lex->token(cur_tok);
210 		n=alloc(RecipeNode::include);
211 		n->AppendSibling( ParseExpr());
212 		if (cur_tok.Type() != Token::semicolon)
213 			throw "Syntax error.";
214 		lex->token(cur_tok);
215 		return (n);
216 	case Token::exit:
217 		lex->token(cur_tok);
218 		n=alloc(RecipeNode::exit);
219 		if (cur_tok.Type() != Token::semicolon)
220 			throw "Syntax error.";
221 		lex->token(cur_tok);
222 		return (n);
223 	case Token::foreach:
224 		lex->token(cur_tok);
225 		n=alloc(RecipeNode::foreach);
226 		n->AppendSibling( ParseExpr());
227 		if (n->firstChild->nodeType != RecipeNode::strregexp &&
228 			n->firstChild->nodeType != RecipeNode::regexpr)
229 			throw "Syntax error.";
230 		if (cur_tok.Type() != Token::semicolon)
231 			throw "Syntax error.";
232 		lex->token(cur_tok);
233 		n->AppendSibling( ParseSubStatement() );
234 		return (n);
235 	case Token::importtoken:
236 		lex->token(cur_tok);
237 		n=alloc(RecipeNode::importtoken);
238 		n->AppendSibling( ParseExpr());
239 		if (cur_tok.Type() != Token::semicolon)
240 			throw "Syntax error.";
241 		lex->token(cur_tok);
242 		return (n);
243 	case Token::unset:
244 		lex->token(cur_tok);
245 		n=alloc(RecipeNode::unset);
246 		n->AppendSibling( ParseExpr());
247 		if (cur_tok.Type() != Token::semicolon)
248 			throw "Syntax error.";
249 		lex->token(cur_tok);
250 		return (n);
251 	default:
252 		break;
253 	}
254 	n=ParseExpr();
255 	if (cur_tok.Type() != Token::semicolon)
256 		throw "Syntax error.";
257 	lex->token(cur_tok);
258 	return (n);
259 }
260 
ParseSubStatement()261 RecipeNode *Recipe::ParseSubStatement()
262 {
263 	if (cur_tok.Type() == Token::semicolon)
264 	{
265 		lex->token(cur_tok);
266 		return alloc(RecipeNode::statementlist);
267 	}
268 	return ParseStatement();
269 }
270 
ParseAssign()271 RecipeNode *Recipe::ParseAssign()
272 {
273 RecipeNode *n=ParseLogicalOr();
274 
275 	while (cur_tok.Type() == Token::equals)
276 	{
277 		lex->token(cur_tok);
278 
279 		if (n->nodeType != RecipeNode::qstring)
280 			throw "Syntax error before =";
281 
282 	RecipeNode *o=alloc(RecipeNode::assignment);
283 		o->AppendSibling(n);
284 
285 		n=ParseLogicalOr();
286 		o->AppendSibling(n);
287 		n=o;
288 	}
289 	return (n);
290 }
291 
ParseLogicalOr()292 RecipeNode *Recipe::ParseLogicalOr()
293 {
294 RecipeNode *n=ParseLogicalAnd();
295 
296 	while (cur_tok.Type() == Token::lor)
297 	{
298 		lex->token(cur_tok);
299 
300 	RecipeNode *o=alloc(RecipeNode::logicalor);
301 
302 		o->AppendSibling(n);
303 
304 		n=ParseLogicalAnd();
305 		o->AppendSibling(n);
306 		n=o;
307 	}
308 	return (n);
309 }
310 
ParseLogicalAnd()311 RecipeNode *Recipe::ParseLogicalAnd()
312 {
313 RecipeNode *n=ParseComparison();
314 
315 	while (cur_tok.Type() == Token::land)
316 	{
317 		lex->token(cur_tok);
318 
319 	RecipeNode *o=alloc(RecipeNode::logicaland);
320 
321 		o->AppendSibling(n);
322 
323 		n=ParseComparison();
324 		o->AppendSibling(n);
325 		n=o;
326 	}
327 	return (n);
328 }
329 
ParseComparison()330 RecipeNode *Recipe::ParseComparison()
331 {
332 RecipeNode *n=ParseBitwiseOr();
333 RecipeNode *o;
334 
335 	switch (cur_tok.Type())	{
336 	case Token::lt:
337 		o=alloc(RecipeNode::lessthan);
338 		break;
339 	case Token::le:
340 		o=alloc(RecipeNode::lessthanoreq);
341 		break;
342 	case Token::gt:
343 		o=alloc(RecipeNode::greaterthan);
344 		break;
345 	case Token::ge:
346 		o=alloc(RecipeNode::greaterthanoreq);
347 		break;
348 	case Token::eq:
349 		o=alloc(RecipeNode::equal);
350 		break;
351 	case Token::ne:
352 		o=alloc(RecipeNode::notequal);
353 		break;
354 	case Token::slt:
355 		o=alloc(RecipeNode::strlessthan);
356 		break;
357 	case Token::sle:
358 		o=alloc(RecipeNode::strlessthanoreq);
359 		break;
360 	case Token::sgt:
361 		o=alloc(RecipeNode::strgreaterthan);
362 		break;
363 	case Token::sge:
364 		o=alloc(RecipeNode::strgreaterthanoreq);
365 		break;
366 	case Token::seq:
367 		o=alloc(RecipeNode::strequal);
368 		break;
369 	case Token::sne:
370 		o=alloc(RecipeNode::strnotequal);
371 		break;
372 	default:
373 		return (n);
374 	}
375 
376 	lex->token(cur_tok);
377 	o->AppendSibling(n);
378 	n=ParseBitwiseOr();
379 	o->AppendSibling(n);
380 	return (o);
381 }
382 
ParseBitwiseOr()383 RecipeNode *Recipe::ParseBitwiseOr()
384 {
385 RecipeNode *n=ParseBitwiseAnd();
386 
387 	while (cur_tok.Type() == Token::bor)
388 	{
389 		lex->token(cur_tok);
390 
391 	RecipeNode *o=alloc(RecipeNode::bitwiseor);
392 
393 		o->AppendSibling(n);
394 
395 		n=ParseBitwiseAnd();
396 		o->AppendSibling(n);
397 		n=o;
398 	}
399 	return (n);
400 }
401 
ParseBitwiseAnd()402 RecipeNode *Recipe::ParseBitwiseAnd()
403 {
404 RecipeNode *n=ParseAddSub();
405 
406 	while (cur_tok.Type() == Token::band)
407 	{
408 		lex->token(cur_tok);
409 
410 	RecipeNode *o=alloc(RecipeNode::bitwiseand);
411 
412 		o->AppendSibling(n);
413 
414 		n=ParseAddSub();
415 		o->AppendSibling(n);
416 		n=o;
417 	}
418 	return (n);
419 }
420 
ParseAddSub()421 RecipeNode *Recipe::ParseAddSub()
422 {
423 RecipeNode *n=ParseMultDiv();
424 RecipeNode *o;
425 
426 	for (;;)	{
427 		switch (cur_tok.Type())	{
428 		case Token::plus:
429 			o=alloc(RecipeNode::add);
430 			break;
431 		case Token::minus:
432 			o=alloc(RecipeNode::subtract);
433 			break;
434 		default:
435 			return (n);
436 		}
437 
438 		lex->token(cur_tok);
439 		o->AppendSibling(n);
440 		n=ParseMultDiv();
441 		o->AppendSibling(n);
442 		n=o;
443 	}
444 }
445 
ParseMultDiv()446 RecipeNode *Recipe::ParseMultDiv()
447 {
448 RecipeNode *n=ParseStrRegExp();
449 RecipeNode *o;
450 
451 	for (;;)	{
452 		switch (cur_tok.Type())	{
453 		case Token::mult:
454 			o=alloc(RecipeNode::multiply);
455 			break;
456 		case Token::divi:
457 			o=alloc(RecipeNode::divide);
458 			break;
459 		default:
460 			return (n);
461 		}
462 
463 		lex->token(cur_tok);
464 		o->AppendSibling(n);
465 		n=ParseElement();
466 		o->AppendSibling(n);
467 		n=o;
468 	}
469 }
470 
ParseStrRegExp()471 RecipeNode *Recipe::ParseStrRegExp()
472 {
473 RecipeNode	*n=ParseElement();
474 
475 	while ( cur_tok.Type() == Token::strregexp)
476 	{
477 	RecipeNode	*o;
478 
479 		o=alloc(RecipeNode::strregexp);
480 		lex->token(cur_tok);
481 		o->AppendSibling(n);
482 		if (cur_tok.Type() != Token::regexpr)
483 			throw "Syntax error after =~";
484 
485 		n=ParseElement();
486 		o->AppendSibling(n);
487 		n=o;
488 	}
489 	return (n);
490 }
491 
ParseElement()492 RecipeNode *Recipe::ParseElement()
493 {
494 RecipeNode	*n, *o;
495 
496 	switch (cur_tok.Type())	{
497 	case Token::length:
498 		n=alloc(RecipeNode::strlength);
499 		lex->token(cur_tok);
500 		o=ParseElement();
501 		n->AppendSibling(o);
502 		return (n);
503 	case Token::substr:
504 		n=alloc(RecipeNode::strsubstr);
505 		lex->token(cur_tok);
506 		if (cur_tok.Type() != Token::lparen)
507 			throw "Missing (";
508 
509 		lex->token(cur_tok);
510 		o=ParseExpr();
511 		n->AppendSibling(o);
512 		if (cur_tok.Type() != Token::comma)
513 			throw "Missing ,";
514 
515 		lex->token(cur_tok);
516 		o=ParseExpr();
517 		n->AppendSibling(o);
518 		if (cur_tok.Type() == Token::comma)
519 		{
520 			lex->token(cur_tok);
521 			o=ParseExpr();
522 			n->AppendSibling(o);
523 		}
524 		if (cur_tok.Type() != Token::rparen)
525 			throw "Missing )";
526 
527 		lex->token(cur_tok);
528 		return (n);
529 	case Token::getaddr:
530 		lex->token(cur_tok);
531 		n=alloc(RecipeNode::getaddr);
532 		n->AppendSibling(ParseElement());
533 		return (n);
534 	case Token::escape:
535 		lex->token(cur_tok);
536 		n=alloc(RecipeNode::escape);
537 		n->AppendSibling(ParseElement());
538 		return (n);
539 	case Token::regexpr:
540 		n=alloc(RecipeNode::regexpr);
541 		n->str=cur_tok.String();
542 		lex->token(cur_tok);
543 		return (n);
544 	case Token::lparen:
545 		lex->token(cur_tok);
546 		n=ParseExpr();
547 		if (cur_tok.Type() != Token::rparen)
548 			throw "Missing )";
549 
550 		lex->token(cur_tok);
551 		return (n);
552 	case Token::logicalnot:
553 		lex->token(cur_tok);
554 		n=alloc(RecipeNode::logicalnot);
555 		o=ParseElement();
556 		n->AppendSibling(o);
557 		return (n);
558 	case Token::bitwisenot:
559 		lex->token(cur_tok);
560 		n=alloc(RecipeNode::bitwisenot);
561 		o=ParseElement();
562 		n->AppendSibling(o);
563 		return (n);
564 	case Token::lookup:
565 		n=alloc(RecipeNode::lookup);
566 		lex->token(cur_tok);
567 		if (cur_tok.Type() != Token::lparen)
568 			throw "Missing (";
569 
570 		lex->token(cur_tok);
571 		o=ParseExpr();
572 		n->AppendSibling(o);
573 		if (cur_tok.Type() != Token::comma)
574 			throw "Missing ,";
575 
576 		lex->token(cur_tok);
577 		o=ParseExpr();
578 		n->AppendSibling(o);
579 		if (cur_tok.Type() == Token::comma)
580 		{
581 			lex->token(cur_tok);
582 			o=ParseExpr();
583 			n->AppendSibling(o);
584 		}
585 		if (cur_tok.Type() != Token::rparen)
586 			throw "Missing )";
587 		lex->token(cur_tok);
588 		return (n);
589 	case Token::to_lower:
590 		lex->token(cur_tok);
591 		n=alloc(RecipeNode::to_lower);
592 		n->AppendSibling(ParseElement());
593 		return (n);
594 	case Token::to_upper:
595 		lex->token(cur_tok);
596 		n=alloc(RecipeNode::to_upper);
597 		n->AppendSibling(ParseElement());
598 		return (n);
599 	case Token::hasaddr:
600 		lex->token(cur_tok);
601 		n=alloc(RecipeNode::hasaddr);
602 		n->AppendSibling(ParseElement());
603 		return (n);
604 #ifdef	DbObj
605 	case Token::gdbmopen:
606 		lex->token(cur_tok);
607 		if (cur_tok.Type() != Token::lparen)
608 			throw "Missing (.";
609 
610 		lex->token(cur_tok);
611 		n=alloc(RecipeNode::gdbmopen);
612 		o=ParseExpr();
613 		n->AppendSibling(o);
614 		if (cur_tok.Type() == Token::comma)
615 		{
616 			lex->token(cur_tok);
617 			o=ParseExpr();
618 			n->AppendSibling(o);
619 		}
620 		if (cur_tok.Type() != Token::rparen)
621 			throw "Missing )";
622 		lex->token(cur_tok);
623 		return (n);
624 	case Token::gdbmclose:
625 		lex->token(cur_tok);
626 		return (alloc(RecipeNode::gdbmclose));
627 	case Token::gdbmfetch:
628 		lex->token(cur_tok);
629 		if (cur_tok.Type() != Token::lparen)
630 			throw "Missing (.";
631 
632 		lex->token(cur_tok);
633 		n=alloc(RecipeNode::gdbmfetch);
634 		o=ParseExpr();
635 		n->AppendSibling(o);
636 		if (cur_tok.Type() == Token::comma)
637 		{
638 			lex->token(cur_tok);
639 			o=ParseExpr();
640 			n->AppendSibling(o);
641 		}
642 		if (cur_tok.Type() == Token::comma)
643 		{
644 			lex->token(cur_tok);
645 			o=ParseExpr();
646 			n->AppendSibling(o);
647 		}
648 		if (cur_tok.Type() != Token::rparen)
649 			throw "Missing )";
650 		lex->token(cur_tok);
651 		return (n);
652 	case Token::gdbmstore:
653 		lex->token(cur_tok);
654 		if (cur_tok.Type() != Token::lparen)
655 			throw "Missing (.";
656 
657 		lex->token(cur_tok);
658 		n=alloc(RecipeNode::gdbmstore);
659 		o=ParseExpr();
660 		n->AppendSibling(o);
661 		if (cur_tok.Type() != Token::comma)
662 			throw "Missing ,.";
663 
664 		lex->token(cur_tok);
665 		o=ParseExpr();
666 		n->AppendSibling(o);
667 		if (cur_tok.Type() != Token::rparen)
668 			throw "Missing )";
669 		lex->token(cur_tok);
670 		return (n);
671 #else
672 	case Token::gdbmopen:
673 	case Token::gdbmclose:
674 	case Token::gdbmfetch:
675 	case Token::gdbmstore:
676 		throw "GDBM/DB support is not available.";
677 #endif
678 	case Token::timetoken:
679 		lex->token(cur_tok);
680 		return (alloc(RecipeNode::timetoken));
681 	default:
682 		break;
683 	}
684 	return (ParseString());
685 }
686 
687 ////////////////////////////////////////////////////////////////////////////
688 //
689 //  Parse a string.  Consecutive strings are automatically concatenated.
690 //
691 ////////////////////////////////////////////////////////////////////////////
692 
ParseString()693 RecipeNode *Recipe::ParseString()
694 {
695 RecipeNode	*n=NULL;
696 RecipeNode	*s=NULL;
697 
698 	for (;;)
699 	{
700 		if (s && s->nodeType != RecipeNode::concat)
701 		{
702 			n=alloc(RecipeNode::concat);
703 			n->AppendSibling(s);
704 			s=n;
705 		}
706 
707 		switch (cur_tok.Type())	{
708 		case Token::qstring:
709 			n=alloc(RecipeNode::qstring);
710 			break;
711 		case Token::sqstring:
712 			n=alloc(RecipeNode::sqstring);
713 			break;
714 		case Token::btstring:
715 			n=alloc(RecipeNode::btstring);
716 			break;
717 		default:
718 			throw "Syntax error.";
719 		}
720 
721 		n->str=cur_tok.String();
722 		lex->token(cur_tok);
723 		if (s)	s->AppendSibling(n);
724 		else	s=n;
725 
726 		switch (cur_tok.Type())	{
727 		case Token::qstring:
728 		case Token::sqstring:
729 		case Token::btstring:
730 			continue;
731 		default:
732 			break;
733 		}
734 		break;
735 	}
736 	return (s);
737 }
738