Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
/*
2
 * MS-DOS SHELL - Symantic Parser
3
 *
4
 * MS-DOS SHELL - Copyright (c) 1990,4 Data Logic Limited and Charles Forsyth
5
 *
6
 * This code is based on (in part) the shell program written by Charles
7
 * Forsyth and the subsequence modifications made by Simon J. Gerraty (for
8
 * his Public Domain Korn Shell) and is subject to the following copyright
9
 * restrictions:
10
 *
11
 * 1.  Redistribution and use in source and binary forms are permitted
12
 *     provided that the above copyright notice is duplicated in the
13
 *     source form and the copyright notice in file sh6.c is displayed
14
 *     on entry to the program.
15
 *
16
 * 2.  The sources (or parts thereof) or objects generated from the sources
17
 *     (or parts of sources) cannot be sold under any circumstances.
18
 *
19
 *
20
 *    $Header: /cvsroot/device/DEVL/UTILS/SH/SH2.C,v 1.1 2002/08/02 06:49:32 adamy Exp $
21
 *
22
 *    $Log: SH2.C,v $
23
 *    Revision 1.1  2002/08/02 06:49:32  adamy
24
 *    imported (reference only)
25
 *
26
 *    Revision 1.1  2001/07/20 05:55:42  ayoung
27
 *    WIN32 support
28
 *
29
 *    Revision 1.1.1.1  1999/12/02 01:11:12  gordonh
30
 *    UTIL
31
 *
32
 *	Revision 2.12  1994/08/25  20:49:11  istewart
33
 *	MS Shell 2.3 Release
34
 *
35
 *	Revision 2.11  1994/02/01  10:25:20  istewart
36
 *	Release 2.3 Beta 2, including first NT port
37
 *
38
 *	Revision 2.10  1994/01/11  17:55:25  istewart
39
 *	Release 2.3 Beta 0 patches
40
 *
41
 *	Revision 2.9  1993/08/25  16:03:57  istewart
42
 *	Beta 225 - see Notes file
43
 *
44
 *	Revision 2.8  1993/07/02  10:21:35  istewart
45
 *	224 Beta fixes
46
 *
47
 *	Revision 2.7  1993/06/14  11:00:12  istewart
48
 *	More changes for 223 beta
49
 *
50
 *	Revision 2.6  1993/06/02  09:52:35  istewart
51
 *	Beta 223 Updates - see Notes file
52
 *
53
 *	Revision 2.5  1993/02/16  16:03:15  istewart
54
 *	Beta 2.22 Release
55
 *
56
 *	Revision 2.4  1993/01/26  18:35:09  istewart
57
 *	Release 2.2 beta 0
58
 *
59
 *	Revision 2.3  1992/11/06  10:03:44  istewart
60
 *	214 Beta test updates
61
 *
62
 *	Revision 2.2  1992/09/03  18:54:45  istewart
63
 *	Beta 213 Updates
64
 *
65
 *	Revision 2.1  1992/07/10  10:52:48  istewart
66
 *	211 Beta updates
67
 *
68
 *	Revision 2.0  1992/04/13  17:39:09  Ian_Stewartson
69
 *	MS-Shell 2.0 Baseline release
70
 *
71
 */
72
 
73
#include <sys/types.h>
74
#include <sys/stat.h>
75
#include <stdio.h>
76
#include <stddef.h>
77
#include <signal.h>
78
#include <errno.h>
79
#include <setjmp.h>
80
#include <string.h>
81
#include <ctype.h>
82
#include <unistd.h>
83
#include <limits.h>
84
#include <dirent.h>
85
#include "sh.h"
86
 
87
static C_Op * F_LOCAL	ScanPipeSyntax (int);
88
static C_Op * F_LOCAL	ScanAndOrSyntax (void);
89
static C_Op * F_LOCAL	CommandList (void);
90
static IO_Actions * F_LOCAL SynchroniseIOList (int);
91
static void F_LOCAL	CheckNextTokenIS (int, int);
92
static void F_LOCAL	SyntaxError (char *);
93
static C_Op * F_LOCAL	ScanNestedSyntax (int, int);
94
static C_Op * F_LOCAL	ScanSimpleCommand (int);
95
static C_Op * F_LOCAL	GetDoDoneCommandList (void);
96
static C_Op * F_LOCAL	ThenPartList (void);
97
static C_Op * F_LOCAL	ElsePartList (void);
98
static C_Op * F_LOCAL	CaseList (void);
99
static C_Op * F_LOCAL	CaseListEntries (void);
100
static char ** F_LOCAL	GetINWordList (void);
101
static C_Op * F_LOCAL	SetupTreeNode (int, C_Op *, C_Op *, char **);
102
static C_Op * F_LOCAL	CreateTreeNode (void);
103
static C_Op * F_LOCAL	yyparse (void);
104
static char * F_LOCAL	LookUpToken (int);
105
static int F_LOCAL	GetNextToken (int);
106
static int F_LOCAL	LookAtNextToken (int);
107
static char * F_LOCAL	MemoryDup (char *, size_t);
108
 
109
static char		*LIT_2ManyRedir = "Too many redirections";
110
static char		*LIT_Expecting = "%s - Expecting '%s', found '%s'";
111
 
112
/*
113
 * Special strings for (( and ))
114
 */
115
 
116
static char		LIT_ODP [] = {
117
    WORD_CHAR,
118
    CHAR_OPEN_PARATHENSIS,
119
    WORD_CHAR,
120
    CHAR_OPEN_PARATHENSIS,
121
 
122
};
123
 
124
static char		LIT_CDP [] = {
125
    WORD_CHAR,
126
    CHAR_CLOSE_PARATHENSIS,
127
    WORD_CHAR,
128
    CHAR_CLOSE_PARATHENSIS,
129
 
130
};
131
 
132
/* Special [[ */
133
 
134
static char		LIT_ODB [] = {
135
    WORD_CHAR,
136
    CHAR_OPEN_BRACKETS,
137
    WORD_CHAR,
138
    CHAR_OPEN_BRACKETS,
139
 
140
};
141
 
142
/*
143
 * Other statics
144
 */
145
 
146
static bool		reject;		/* GetNextToken(cf) gets symbol	*/
147
					/* again			*/
148
static int		symbol;		/* yylex value			*/
149
 
150
#define NEWNODE		((C_Op *)CreateTreeNode ())
151
#define	REJECT		(reject = TRUE)
152
#define	ACCEPT		(reject = FALSE)
153
 
154
/*
155
 * Get the next token from input
156
 */
157
 
158
static int F_LOCAL	GetNextToken (int cf)
159
{
160
    if (reject)
161
	ACCEPT;
162
 
163
    else
164
    {
165
	symbol = ScanNextToken (cf);
166
	ACCEPT;
167
    }
168
 
169
    return symbol;
170
}
171
 
172
/*
173
 * Look at the next token from input
174
 */
175
 
176
static int F_LOCAL	LookAtNextToken (int cf)
177
{
178
    if (!reject)
179
    {
180
	symbol = ScanNextToken (cf);
181
	REJECT;
182
    }
183
 
184
    return symbol;
185
}
186
 
187
/*
188
 * Parse the current input stack
189
 */
190
 
191
static C_Op * F_LOCAL yyparse (void)
192
{
193
    C_Op	*t;		/* yyparse output */
194
 
195
    ACCEPT;
196
    yynerrs = 0;
197
 
198
/* Check for EOF */
199
 
200
    if ((LookAtNextToken (ALLOW_KEYWORD | ALLOW_ALIAS)) == 0)
201
    {
202
	(t = NEWNODE)->type = TEOF;
203
	DPRINT (1, ("yyparse: Create TEOF"));
204
    }
205
 
206
    else
207
    {
208
	t = CommandList ();
209
	CheckNextTokenIS (CHAR_NEW_LINE, 0);
210
    }
211
 
212
    return t;
213
}
214
 
215
/*
216
 * Check a pipeline
217
 */
218
 
219
static C_Op * F_LOCAL ScanPipeSyntax (int LexicalControlFlags)
220
{
221
    C_Op	*t, *p, *tl = NULL;
222
 
223
    if ((t = ScanSimpleCommand (LexicalControlFlags)) != (C_Op *)NULL)
224
    {
225
	while (GetNextToken (0) == CHAR_PIPE)
226
	{
227
	    if ((p = ScanSimpleCommand (ALLOW_CONTINUATION)) == NULL)
228
		SyntaxError ("no commands found following pipe");
229
 
230
	    if (tl == NULL)
231
	    {
232
		tl = SetupTreeNode (TPIPE, t, p, NOWORDS);
233
		t = tl;
234
	    }
235
 
236
	    else
237
	    {
238
		tl->right = SetupTreeNode (TPIPE, tl->right, p, NOWORDS);
239
		tl = tl->right;
240
	    }
241
	}
242
 
243
	REJECT;
244
    }
245
 
246
    return t;
247
}
248
 
249
static C_Op * F_LOCAL ScanAndOrSyntax (void)
250
{
251
    C_Op	*t, *p;
252
    int		c;
253
 
254
    t = ScanPipeSyntax (0);
255
 
256
    if (t != NULL)
257
    {
258
	while (((c = GetNextToken (0)) == PARSE_LOGICAL_AND) ||
259
	       (c == PARSE_LOGICAL_OR))
260
	{
261
	    if ((p = ScanPipeSyntax (ALLOW_CONTINUATION)) == NULL)
262
		SyntaxError ("no commands found following || or &&");
263
 
264
	    t = SetupTreeNode ((c == PARSE_LOGICAL_AND) ? TAND : TOR, t, p,
265
			       NOWORDS);
266
	}
267
 
268
	REJECT;
269
    }
270
 
271
    return t;
272
}
273
 
274
static C_Op *F_LOCAL CommandList (void)
275
{
276
    C_Op	*t, *p, *tl = NULL;
277
    int		c;
278
 
279
    if ((t = ScanAndOrSyntax ()) != NULL)
280
    {
281
	while (((c = GetNextToken (0)) == CHAR_SEPARATOR) ||
282
	       (c == CHAR_ASYNC) || (c == PARSE_COPROCESS) ||
283
	       ((AllowMultipleLines ||
284
	        (source->type == SSTRING) ||
285
		(source->type == SALIAS)) && (c == CHAR_NEW_LINE)))
286
	{
287
	    if ((c == CHAR_ASYNC) || (c == PARSE_COPROCESS))
288
	    {
289
		c = (c == CHAR_ASYNC) ? TASYNC : TCOPROCESS;
290
 
291
		if (tl)
292
		    tl->right = SetupTreeNode (c, tl->right, NOBLOCK, NOWORDS);
293
 
294
		else
295
		    t = SetupTreeNode (c, t, NOBLOCK, NOWORDS);
296
	    }
297
 
298
	    if ((p = ScanAndOrSyntax ()) == NULL)
299
		return t;
300
 
301
	    if (tl == NULL)
302
	    {
303
		tl = SetupTreeNode (TLIST, t, p, NOWORDS);
304
		t = tl;
305
	    }
306
 
307
	    else
308
	    {
309
		tl->right = SetupTreeNode (TLIST, tl->right, p, NOWORDS);
310
		tl = tl->right;
311
	    }
312
	}
313
 
314
	REJECT;
315
    }
316
 
317
    return t;
318
}
319
 
320
/*
321
 * Handle IO re-direction
322
 */
323
 
324
static IO_Actions * F_LOCAL SynchroniseIOList (int LexicalControlFlags)
325
{
326
    IO_Actions		*iop;
327
 
328
    if (LookAtNextToken (LexicalControlFlags) != PARSE_REDIR)
329
	return (IO_Actions *)NULL;
330
 
331
    ACCEPT;
332
    iop = yylval.iop;
333
    CheckNextTokenIS (PARSE_WORD, 0);
334
    iop->io_name = yylval.cp;
335
 
336
    if ((iop->io_flag & IOTYPE) == IOHERE)
337
    {
338
	if (*CurrentLexIdentifier != 0) /* unquoted */
339
	    iop->io_flag |= IOEVAL;
340
 
341
	SaveHereDocumentInfo (iop);
342
    }
343
 
344
    return iop;
345
}
346
 
347
static void F_LOCAL CheckNextTokenIS (int c, int LexicalControlFlags)
348
{
349
    int		got;
350
 
351
    if ((got = GetNextToken (LexicalControlFlags)) != c)
352
    {
353
	CompilingError ();
354
	ShellErrorMessage (LIT_Expecting, LIT_SyntaxError, LookUpToken (c),
355
			   LookUpToken (got));
356
    }
357
}
358
 
359
/*
360
 * Handle Nested thingys - ( and {
361
 */
362
 
363
static C_Op * F_LOCAL ScanNestedSyntax (int type, int mark)
364
{
365
    C_Op	*t;
366
 
367
    AllowMultipleLines++;
368
    t = CommandList ();
369
    CheckNextTokenIS (mark, ALLOW_KEYWORD);
370
    AllowMultipleLines--;
371
    return SetupTreeNode (type, t, NOBLOCK, NOWORDS);
372
}
373
 
374
/*
375
 * Handle a single command and its bits and pieces - IO redirection,
376
 * arguments and variable assignments
377
 */
378
 
379
static C_Op * F_LOCAL ScanSimpleCommand (int LexicalControlFlags)
380
{
381
    C_Op	*t;
382
    int			c;
383
    IO_Actions		*iop;
384
    Word_B		*Arguments = (Word_B *)NULL;
385
    Word_B		*Variables = (Word_B *)NULL;
386
    Word_B		*IOactions = (Word_B *)NULL;
387
 
388
/* Allocate space for IO actions structures */
389
 
390
    if (AllowMultipleLines)
391
	LexicalControlFlags = ALLOW_CONTINUATION;
392
 
393
    LexicalControlFlags |= ALLOW_KEYWORD | ALLOW_ALIAS;
394
 
395
    while ((iop = SynchroniseIOList (LexicalControlFlags)) != NULL)
396
    {
397
	if (WordBlockSize (IOactions) >= NUFILE)
398
	{
399
	    CompilingError ();
400
	    ShellErrorMessage (LIT_2ManyRedir);
401
	}
402
 
403
	IOactions = AddWordToBlock ((char *)iop, IOactions);
404
	LexicalControlFlags &=~ ALLOW_CONTINUATION;
405
    }
406
 
407
    switch (c = GetNextToken (LexicalControlFlags))
408
    {
409
	case 0:
410
	    CompilingError ();
411
	    ShellErrorMessage ("unexpected EOF");
412
	    return NULL;
413
 
414
	case CHAR_SEPARATOR:
415
	    REJECT;
416
	    (t = NEWNODE)->type = TCOM;
417
	    DPRINT (1, ("ScanSimpleCommand: Create TCOM"));
418
	    break;
419
 
420
	default:
421
	    REJECT;
422
 
423
	    if (WordBlockSize (IOactions) == 0)
424
		return (C_Op *)NULL;		/* empty line		*/
425
 
426
	    (t = NEWNODE)->type = TCOM;
427
	    DPRINT (1, ("ScanSimpleCommand: Create TCOM"));
428
	    break;
429
 
430
	case PARSE_WORD:
431
	case PARSE_MDPAREN:
432
	    REJECT;
433
	    (t = NEWNODE)->type = TCOM;
434
	    DPRINT (1, ("ScanSimpleCommand: Create TCOM"));
435
 
436
	    if (c == PARSE_MDPAREN)
437
	    {
438
		ACCEPT;
439
		Arguments = AddWordToBlock (MemoryDup (LIT_ODP, 5), Arguments);
440
		CheckNextTokenIS (PARSE_WORD, MATHS_EXPRESSION);
441
		Arguments = AddWordToBlock (yylval.cp, Arguments);
442
		Arguments = AddWordToBlock (MemoryDup (LIT_CDP, 5), Arguments);
443
	    }
444
 
445
	    while (1)
446
	    {
447
		switch (LookAtNextToken (0))
448
		{
449
		    case PARSE_REDIR:
450
			if (WordBlockSize (IOactions) >= NUFILE)
451
			{
452
			    CompilingError ();
453
			    ShellErrorMessage (LIT_2ManyRedir);
454
			}
455
 
456
			IOactions = AddWordToBlock (
457
					(char *)SynchroniseIOList (0),
458
					IOactions);
459
			break;
460
 
461
/*
462
 * Word - check to see if this should be an argument or a variable,
463
 * depending on what we've seen, the state of the k flag and an
464
 * assignment in the word
465
 */
466
 
467
		    case PARSE_WORD:
468
			ACCEPT;
469
			if (((WordBlockSize (Arguments) == 0) ||
470
			     FL_TEST (FLAG_ALL_KEYWORDS)) &&
471
			    (strchr (CurrentLexIdentifier + 1, CHAR_ASSIGN) !=
472
					(char *)NULL))
473
			    Variables = AddWordToBlock (yylval.cp, Variables);
474
 
475
			else
476
			    Arguments = AddWordToBlock (yylval.cp, Arguments);
477
 
478
			break;
479
 
480
		    case PARSE_MPAREN:
481
			ACCEPT;
482
 
483
			if (WordBlockSize (Arguments) != 1)
484
			    SyntaxError ("Too many function names");
485
 
486
			if (*CurrentLexIdentifier == 0)
487
			    SyntaxError ("Bad function name");
488
 
489
			(t = NEWNODE)->type = TFUNC;
490
			DPRINT (1, ("ScanSimpleCommand: Create TFUNC"));
491
			t->str = StringCopy (CurrentLexIdentifier);
492
			CheckNextTokenIS (CHAR_OPEN_BRACES,
493
					  ALLOW_CONTINUATION | ALLOW_KEYWORD);
494
			t->left = ScanNestedSyntax (TBRACE, CHAR_CLOSE_BRACES);
495
			return t;
496
 
497
		    default:
498
			goto Leave;
499
		}
500
	    }
501
Leave:
502
	    break;
503
 
504
	case CHAR_OPEN_PARATHENSIS:
505
	    t = ScanNestedSyntax (TPAREN, CHAR_CLOSE_PARATHENSIS);
506
	    break;
507
 
508
	case CHAR_OPEN_BRACES:
509
	    t = ScanNestedSyntax (TBRACE, CHAR_CLOSE_BRACES);
510
	    break;
511
 
512
/*
513
 * Format for:  [[ .....  ]]
514
 */
515
 
516
	case PARSE_TEST:
517
	    (t = NEWNODE)->type = TCOM;
518
	    DPRINT (1, ("ScanSimpleCommand: Create TCOM"));
519
	    Arguments = AddWordToBlock (MemoryDup (LIT_ODB, 5), Arguments);
520
 
521
	    while (GetNextToken (TEST_EXPRESSION) == PARSE_WORD)
522
	    {
523
		Arguments = AddWordToBlock (yylval.cp, Arguments);
524
 
525
		if (strcmp (CurrentLexIdentifier , "]]") == 0)
526
		    break;
527
	    }
528
 
529
	    break;
530
 
531
/*
532
 * Format for:	select word in list do .... done
533
 * 		select word do .... done
534
 *		for word in list do .... done
535
 * 		for word do .... done
536
 */
537
 
538
	case PARSE_FOR:
539
	case PARSE_SELECT:
540
	    (t = NEWNODE)->type = (c == PARSE_FOR) ? TFOR : TSELECT;
541
	    DPRINT (1, ("ScanSimpleCommand: Create TFOR/TSELECT"));
542
	    CheckNextTokenIS (PARSE_WORD, 0);
543
	    t->str = StringCopy (CurrentLexIdentifier);
544
	    AllowMultipleLines++;
545
	    t->vars = GetINWordList ();
546
	    t->left = GetDoDoneCommandList ();
547
	    AllowMultipleLines--;
548
	    break;
549
 
550
 
551
/*
552
 * Format for:	while command do ... done
553
 * 		until command do ... done
554
 */
555
 
556
	case PARSE_WHILE:
557
	case PARSE_UNTIL:
558
	    AllowMultipleLines++;
559
	    (t = NEWNODE)->type = (c == PARSE_WHILE) ? TWHILE : TUNTIL;
560
	    DPRINT (1, ("ScanSimpleCommand: Create TWHILE/TUNTIL"));
561
	    t->left = CommandList ();
562
	    t->right = GetDoDoneCommandList ();
563
	    AllowMultipleLines--;
564
	    break;
565
 
566
/*
567
 * Format for:	case name in .... esac
568
 */
569
 
570
	case PARSE_CASE:
571
	    (t = NEWNODE)->type = TCASE;
572
	    DPRINT (1, ("ScanSimpleCommand: Create TCASE"));
573
	    CheckNextTokenIS (PARSE_WORD, 0);
574
	    t->str = yylval.cp;
575
	    AllowMultipleLines++;
576
	    CheckNextTokenIS (PARSE_IN, ALLOW_KEYWORD | ALLOW_CONTINUATION);
577
	    t->left = CaseList ();
578
	    CheckNextTokenIS (PARSE_ESAC, ALLOW_KEYWORD);
579
	    AllowMultipleLines--;
580
	    break;
581
 
582
/*
583
 * Format for:	if command then command fi
584
 *		if command then command else command fi
585
 *		if command then command elif command then ... else ... fi
586
 */
587
 
588
	case PARSE_IF:
589
	    AllowMultipleLines++;
590
	    (t = NEWNODE)->type = TIF;
591
	    DPRINT (1, ("ScanSimpleCommand: Create TIF"));
592
	    t->left = CommandList ();
593
	    t->right = ThenPartList ();
594
	    CheckNextTokenIS (PARSE_FI, ALLOW_KEYWORD);
595
	    AllowMultipleLines--;
596
	    break;
597
 
598
/*
599
 * Format for: time command
600
 */
601
 
602
	case PARSE_TIME:
603
	    t = ScanPipeSyntax (ALLOW_CONTINUATION);
604
	    t = SetupTreeNode (TTIME, t, NOBLOCK, NOWORDS);
605
	    break;
606
 
607
/*
608
 * Format for:  function name { .... }
609
 */
610
 
611
	case PARSE_FUNCTION:
612
	    (t = NEWNODE)->type = TFUNC;
613
	    DPRINT (1, ("ScanSimpleCommand: Create TFUNC"));
614
	    CheckNextTokenIS (PARSE_WORD, 0);
615
	    t->str = StringCopy (CurrentLexIdentifier);
616
	    CheckNextTokenIS (CHAR_OPEN_BRACES,
617
			      (ALLOW_CONTINUATION | ALLOW_KEYWORD));
618
	    t->left = ScanNestedSyntax (TBRACE, CHAR_CLOSE_BRACES);
619
	    break;
620
    }
621
 
622
/* Get any remaining IOactions */
623
 
624
    while ((iop = SynchroniseIOList (ALLOW_KEYWORD)) != NULL)
625
    {
626
	if (WordBlockSize (IOactions) >= NUFILE)
627
	{
628
	    CompilingError ();
629
	    ShellErrorMessage (LIT_2ManyRedir);
630
	}
631
 
632
	IOactions = AddWordToBlock ((char *)iop, IOactions);
633
    }
634
 
635
/* Save the IOactions */
636
 
637
    if (WordBlockSize (IOactions) == 0)
638
	t->ioact = (IO_Actions **)NULL;
639
 
640
    else
641
	t->ioact = (IO_Actions **) GetWordList (AddWordToBlock (NOWORD,
642
								IOactions));
643
 
644
/* If TCOM, save the arguments and variable assignments */
645
 
646
    if (t->type == TCOM)
647
    {
648
	t->args = GetWordList (AddWordToBlock (NOWORD, Arguments));
649
	t->vars = GetWordList (AddWordToBlock (NOWORD, Variables));
650
    }
651
 
652
/* Handle re-direction on other pipelines */
653
 
654
    else if ((t->type != TPAREN) && (t->ioact != (IO_Actions **)NULL))
655
    {
656
	C_Op		*t1 = t;
657
 
658
	(t = NEWNODE)->type = TPAREN;
659
	DPRINT (1, ("ScanSimpleCommand: Create TPAREN"));
660
	t->left = t1;
661
	t->right = NOBLOCK;
662
	t->args = NOWORDS;
663
	t->vars = NOWORDS;
664
	t->ioact = t1->ioact;
665
	t1->ioact = (IO_Actions **)NULL;
666
    }
667
 
668
/*
669
 * We should probably release IOactions, Arguments and Variables if they
670
 * are not used.  However, I don't think its necessary.  The release memory
671
 * level should do it.
672
 */
673
 
674
    return t;
675
}
676
 
677
 
678
/*
679
 * Processing for the do grouping - do ... done
680
 */
681
 
682
static C_Op * F_LOCAL GetDoDoneCommandList (void)
683
{
684
    int		c;
685
    C_Op	*list;
686
 
687
    if ((c = GetNextToken (ALLOW_CONTINUATION | ALLOW_KEYWORD)) != PARSE_DO)
688
    {
689
	CompilingError ();
690
	ShellErrorMessage (LIT_Expecting, LIT_SyntaxError, "do",
691
			   LookUpToken (c));
692
    }
693
 
694
    list = CommandList ();
695
    CheckNextTokenIS (PARSE_DONE, ALLOW_KEYWORD);
696
    return list;
697
}
698
 
699
 
700
/*
701
 * Handle the then part of an if statement
702
 */
703
 
704
static C_Op * F_LOCAL ThenPartList (void)
705
{
706
    C_Op	*t;
707
 
708
    if (GetNextToken (0) != PARSE_THEN)
709
    {
710
	REJECT;
711
	return (C_Op *)NULL;
712
    }
713
 
714
    (t = NEWNODE)->type = 0;
715
    DPRINT (1, ("ThenPartList: Create dummy"));
716
 
717
    if ((t->left = CommandList ()) == (C_Op *)NULL)
718
	SyntaxError ("no command found after then");
719
 
720
    t->right = ElsePartList ();
721
    return t;
722
}
723
 
724
 
725
/*
726
 * Handle the else part of an if statement
727
 */
728
 
729
static C_Op * F_LOCAL ElsePartList (void)
730
{
731
    C_Op	*t;
732
 
733
    switch (GetNextToken (0))
734
    {
735
      case PARSE_ELSE:
736
	if ((t = CommandList ()) == (C_Op *)NULL)
737
	    SyntaxError ("no commands associated with else");
738
 
739
	return t;
740
 
741
      case PARSE_ELIF:
742
	(t = NEWNODE)->type = TELIF;
743
	DPRINT (1, ("ElsePartList: Create TELIF"));
744
	t->left = CommandList ();
745
	t->right = ThenPartList ();
746
	return t;
747
 
748
      default:
749
	REJECT;
750
	return (C_Op *)NULL;
751
    }
752
}
753
 
754
 
755
/*
756
 * Process the CASE statment
757
 */
758
 
759
static C_Op * F_LOCAL CaseList (void)
760
{
761
    C_Op	*t = (C_Op *)NULL;
762
    C_Op	*tl = (C_Op *)NULL;
763
 
764
    while ((LookAtNextToken (ALLOW_CONTINUATION | ALLOW_KEYWORD)) != PARSE_ESAC)
765
    {
766
	C_Op	*tc = CaseListEntries ();
767
 
768
	if (tl == (C_Op *)NULL)
769
	{
770
	    t = tc;
771
	    (tl = tc)->right = (C_Op *)NULL;
772
	}
773
 
774
	else
775
	{
776
	    tl->right = tc;
777
	    tl = tc;
778
	}
779
    }
780
 
781
    return t;
782
}
783
 
784
 
785
/*
786
 * Process an individual case entry: pattern) commands;;
787
 */
788
 
789
static C_Op * F_LOCAL CaseListEntries (void)
790
{
791
    C_Op	*t;
792
    int		LexicalControlFlags = ALLOW_CONTINUATION | ALLOW_KEYWORD;
793
    Word_B	*Patterns = (Word_B *)NULL;
794
 
795
    (t = NEWNODE)->type = TPAT;
796
    DPRINT (1, ("CaseListEntries: Create TPAT"));
797
 
798
    if (GetNextToken (LexicalControlFlags) != CHAR_OPEN_PARATHENSIS)
799
	REJECT;
800
 
801
    else
802
	LexicalControlFlags = 0;
803
 
804
    do
805
    {
806
	CheckNextTokenIS (PARSE_WORD, LexicalControlFlags);
807
	Patterns = AddWordToBlock (yylval.cp, Patterns);
808
	LexicalControlFlags = 0;
809
    } while (GetNextToken (0) == CHAR_PIPE);
810
 
811
    REJECT;
812
 
813
/*
814
 * Terminate the list of patterns
815
 */
816
 
817
    t->vars = GetWordList (AddWordToBlock (NOWORD, Patterns));
818
 
819
/*
820
 * Check for the terminating ), and get the command list
821
 */
822
 
823
    CheckNextTokenIS (CHAR_CLOSE_PARATHENSIS, 0);
824
 
825
    t->left = CommandList ();
826
 
827
    if ((LookAtNextToken (ALLOW_CONTINUATION | ALLOW_KEYWORD)) != PARSE_ESAC)
828
	CheckNextTokenIS (PARSE_BREAK, ALLOW_CONTINUATION | ALLOW_KEYWORD);
829
 
830
    return (t);
831
}
832
 
833
 
834
/*
835
 * Handle the in words.... part of a for or select statement.  Get the
836
 * words and build a list.
837
 */
838
 
839
static char ** F_LOCAL GetINWordList (void)
840
{
841
    int		c;
842
    Word_B	*Parameters = (Word_B *)NULL;
843
 
844
/*
845
 * Check to see if the next symbol is "in".  If not there are no words
846
 * following
847
 */
848
 
849
    if ((c = GetNextToken (ALLOW_CONTINUATION | ALLOW_KEYWORD)) != PARSE_IN)
850
    {
851
	REJECT;
852
	return NOWORDS;
853
    }
854
 
855
/* Get the list */
856
 
857
    while ((c = GetNextToken (0)) == PARSE_WORD)
858
	Parameters = AddWordToBlock (yylval.cp, Parameters);
859
 
860
    if ((c != CHAR_NEW_LINE) && (c != CHAR_SEPARATOR))
861
    {
862
	CompilingError ();
863
	ShellErrorMessage (LIT_Expecting, LIT_SyntaxError, "newline' or ';",
864
			   LookUpToken (c));
865
    }
866
 
867
/* Are there any words found? */
868
 
869
    if (Parameters == (Word_B *)NULL)
870
	return NOWORDS;
871
 
872
    return GetWordList (AddWordToBlock (NOWORD, Parameters));
873
}
874
 
875
/*
876
 * supporting functions
877
 */
878
 
879
static C_Op * F_LOCAL SetupTreeNode (int type, C_Op *t1, C_Op *t2, char **wp)
880
{
881
    C_Op	*t;
882
 
883
    (t = NEWNODE)->type = type;
884
    DPRINT (1, ("SetupTreeNode: Create %d", type));
885
    t->left = t1;
886
    t->right = t2;
887
    t->vars = wp;
888
    return t;
889
}
890
 
891
/*
892
 * Get and compile the next command from the user/file etc
893
 */
894
 
895
C_Op	*BuildParseTree (Source *s)
896
{
897
    C_Op	*t;		/* yyparse output */
898
 
899
    yynerrs = 0;
900
    AllowMultipleLines = 0;
901
    source = s;
902
 
903
    t = yyparse ();
904
 
905
    if (s->type == STTY || s->type == SFILE)
906
	s->str = null;			/* line is not preserved	*/
907
 
908
    return yynerrs ? (C_Op *)NULL : t;
909
}
910
 
911
/*
912
 * Get a new tree leaf structure
913
 */
914
 
915
static C_Op * F_LOCAL CreateTreeNode (void)
916
{
917
    C_Op	*t;
918
 
919
    if ((t = (C_Op *)AllocateMemoryCell (sizeof (C_Op))) == (C_Op *)NULL)
920
	ShellErrorMessage ("command line too complicated");
921
 
922
    return t;
923
}
924
 
925
/*
926
 * List of keywords
927
 */
928
 
929
static struct res {
930
    char	*r_name;
931
    int		r_val;
932
} restab[] = {
933
    { "for",	PARSE_FOR},		{ "case",	PARSE_CASE},
934
    { "esac",	PARSE_ESAC},		{ "while",	PARSE_WHILE},
935
    { "do",	PARSE_DO},		{ LIT_done,	PARSE_DONE},
936
    { "if",	PARSE_IF},		{ "in",		PARSE_IN},
937
    { "then",	PARSE_THEN},		{ "else",	PARSE_ELSE},
938
    { "elif",	PARSE_ELIF},		{ "until",	PARSE_UNTIL},
939
    { "fi",	PARSE_FI},		{ "select",	PARSE_SELECT},
940
    { "time",	PARSE_TIME},		{ "function",	PARSE_FUNCTION},
941
    { LIT_Test,	PARSE_TEST},
942
    { "{",	CHAR_OPEN_BRACES},	{ "}",		CHAR_CLOSE_BRACES},
943
 
944
    { (char *)NULL,	0},
945
 
946
/* Additional definitions */
947
 
948
    { "word",	PARSE_WORD},		{ "&&",		PARSE_LOGICAL_AND},
949
    { "||",	PARSE_LOGICAL_OR},	{ "redirection",PARSE_REDIR },
950
    { "(..)",	PARSE_MPAREN},		{ "((...))",	PARSE_MDPAREN},
951
    { "|&",	PARSE_COPROCESS},	{ "newline",'\n'},
952
 
953
    { (char *)NULL,	0}
954
};
955
 
956
int LookUpSymbol (char *n)
957
{
958
    struct res		*rp = restab;
959
 
960
    while ((rp->r_name != (char *)NULL) && strcmp (rp->r_name, n))
961
	rp++;
962
 
963
    return rp->r_val;
964
}
965
 
966
static char * F_LOCAL LookUpToken (int n)
967
{
968
    struct res		*rp = restab;
969
    int			first = TRUE;
970
 
971
    while (TRUE)
972
    {
973
        if ((rp->r_name == (char *)NULL) && !first)
974
	{
975
	    char 	*cp = GetAllocatedSpace (4);
976
 
977
	    if (cp == (char *)NULL)
978
		return (char *)NULL;
979
 
980
	    sprintf (cp, "%c", n);
981
	    return cp;
982
	}
983
 
984
	else if (rp->r_name == (char *)NULL)
985
	    first = FALSE;
986
 
987
	else if (rp->r_val == n)
988
	    return rp->r_name;
989
 
990
	rp++;
991
    }
992
}
993
 
994
/*
995
 * Syntax error
996
 */
997
 
998
static void F_LOCAL SyntaxError (char *emsg)
999
{
1000
    CompilingError ();
1001
    ShellErrorMessage ("%s - %s", LIT_SyntaxError, emsg);
1002
}
1003
 
1004
/*
1005
 * Duplicate a memory string
1006
 */
1007
 
1008
static char * F_LOCAL	MemoryDup (char *string, size_t length)
1009
{
1010
    char	*t;
1011
 
1012
    if ((t = AllocateMemoryCell (length)) == (char *)NULL)
1013
	ShellErrorMessage ("Out of memory");
1014
 
1015
    return memcpy (t, string, length);
1016
}