Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/nmake/parse.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1984-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* makefile lexical scanner and parser
26
*
27
* interleaved recursive parse() and expand() nesting supported
28
*
29
* NOTE: readline() from file does double copy to pp->ip and sp
30
* it should be possible to go directly to sp
31
*/
32
33
#include "make.h"
34
#include "options.h"
35
36
#include <sig.h>
37
38
#define PARSEDEPTH 64 /* maximum parse stack depth */
39
40
#define PS1 "make> " /* primary query prompt */
41
#define PS2 ">>>>> " /* secondary query prompt */
42
43
#define OP_ASSERT (1<<0) /* assertion statement */
44
#define OP_ASSIGN (1<<1) /* assignment statement */
45
#define OP_EMPTY (1<<2) /* no operator found */
46
#define OP_STATEMENT ((1<<3)-1) /* statement type mask */
47
48
#define OP_ACTION (1<<3) /* operator takes action */
49
#define OP_APPEND (1<<4) /* append assignment */
50
#define OP_AUXILIARY (1<<5) /* auxiliary assignment */
51
#define OP_EXPAND (1<<6) /* expand lhs and rhs */
52
#define OP_STATE (1<<7) /* state assignment */
53
54
#define CON_kept (1<<0) /* already kept part of block */
55
#define CON_skip (1<<1) /* skip this part of block */
56
#define CON_stash (1<<2) /* file loop body lines stashed */
57
58
#define CON_if (1<<3) /* if block */
59
#define CON_elif (1<<4) /* not used in flags */
60
#define CON_else (1<<5) /* had else */
61
#define CON_end (1<<6) /* not used in flags */
62
#define CON_for (1<<7) /* for loop block */
63
#define CON_while (1<<8) /* while loop block */
64
#define CON_eval (1<<9) /* eval block */
65
66
#define CON_break (1<<10) /* loop break */
67
#define CON_continue (2<<10) /* loop continue */
68
#define CON_error (3<<10) /* error message output */
69
#define CON_exit (4<<10) /* exit */
70
#define CON_let (5<<10) /* let expression */
71
#define CON_local (6<<10) /* local var declaration */
72
#define CON_print (7<<10) /* standard output message */
73
#define CON_read (8<<10) /* read */
74
#define CON_return (9<<10) /* return */
75
#define CON_rules (10<<10) /* rules */
76
#define CON_set (11<<10) /* set options */
77
78
#define PUSHLOCAL(p) do{for(p=pp->local;p;p=p->next)if(!(p->newv.property&V_scope))p->bucket->value=(char*)p->oldv;}while(0)
79
#define POPLOCAL(p) do{for(p=pp->local;p;p=p->next)if(!(p->newv.property&V_scope))p->bucket->value=(char*)&p->newv;}while(0)
80
81
#define freelocal(x) do{x->next=freelocals;freelocals=x;}while(0)
82
#define newlocal(x) do{if(x=freelocals)freelocals=x->next;else x=newof(0,Local_t,1,0);}while(0)
83
84
struct Local_s; typedef struct Local_s Local_t;
85
86
struct Local_s /* local variable state */
87
{
88
Hash_bucket_t* bucket; /* table.var hash bucket */
89
Var_t* oldv; /* old variable value */
90
Var_t newv; /* new variable info */
91
Local_t* next; /* next in list */
92
int line; /* declaration line number */
93
};
94
95
typedef struct Control_s /* flow control block stack */
96
{
97
int flags; /* block flags */
98
union
99
{
100
char* buffer; /* loop body buffer */
101
size_t offset; /* loop body ip offset */
102
} body;
103
int line; /* loop line number */
104
union
105
{
106
struct
107
{
108
char* test; /* while loop test */
109
int free; /* free test */
110
} w;
111
struct
112
{
113
Var_t* var; /* for loop variable */
114
char** args; /* for loop arg vector */
115
Sfio_t* tmp; /* for loop arg tmp */
116
Sfio_t* vec; /* for loop args tmp */
117
} f;
118
} loop;
119
} Control_t;
120
121
typedef struct Parseinfo_s /* recursive parse state stack */
122
{
123
Control_t* cp; /* control block pointer */
124
Control_t* block; /* control block lo water */
125
126
/* the rest are implicitly initialized */
127
128
int argc; /* local argc */
129
char* name; /* current level input name */
130
char* here; /* <<? termination string */
131
Sfio_t* fp; /* input file pointer */
132
Sfio_t* ip; /* readline write string */
133
Sfio_t* scoped; /* scoped options/assignments */
134
char* bp; /* input buffer pointer */
135
char* stashget; /* loop body stash get */
136
char* pushback; /* line pushback pointer */
137
Local_t* local; /* local variables */
138
int checkhere; /* <<? offset */
139
int line; /* prev level input line number */
140
int splice; /* splice line */
141
short indent; /* active indentation level */
142
unsigned char eval; /* eval block level */
143
unsigned char status; /* action return status */
144
unsigned int newline:1; /* \n at *bp replaced by 0 */
145
unsigned int prompt:1; /* interactive input with prompt*/
146
unsigned int stashput:1; /* put lines in stash */
147
} Parseinfo_t;
148
149
/*
150
* WARNING: getline() uses the first keyword char
151
*/
152
153
static Namval_t controls[] = /* control keywords */
154
{
155
"break", CON_break,
156
"continue", CON_continue,
157
"elif", CON_elif,
158
"else", CON_else,
159
"end", CON_end,
160
"error", CON_error,
161
"eval", CON_eval,
162
"exit", CON_exit,
163
"for", CON_for,
164
"if", CON_if,
165
"let", CON_let,
166
"local", CON_local,
167
"print", CON_print,
168
"read", CON_read,
169
"return", CON_return,
170
"rules", CON_rules,
171
"set", CON_set,
172
"while", CON_while,
173
};
174
175
static Control_t constack[PARSEDEPTH * 3];
176
177
static Parseinfo_t parsestack[PARSEDEPTH] = { &constack[0], &constack[0] };
178
static Parseinfo_t* pp = &parsestack[0];
179
180
static Local_t* freelocals;
181
182
/*
183
* unwind the parse stack to level on errors
184
*/
185
186
void
187
unparse(int level)
188
{
189
register Local_t* lcl;
190
register Local_t* olcl;
191
register Control_t* cp;
192
register Rule_t* r;
193
194
if (pp >= &parsestack[elementsof(parsestack)])
195
pp = &parsestack[elementsof(parsestack) - 1];
196
while (pp > &parsestack[level])
197
{
198
if ((r = getrule(pp->name)) && r->active)
199
{
200
r->active = r->active->previous;
201
if (r->status == UPDATE)
202
r->status = EXISTS;
203
}
204
if (pp->fp)
205
{
206
if (pp->fp != sfstdin)
207
sfclose(pp->fp);
208
sfstrclose(pp->ip);
209
}
210
if (lcl = pp->local)
211
{
212
pp->local = 0;
213
while (lcl)
214
{
215
lcl->bucket->value = (char*)lcl->oldv;
216
olcl = lcl;
217
lcl = lcl->next;
218
freelocal(olcl);
219
}
220
}
221
for (cp = pp->cp; cp > pp->block; cp--)
222
if (cp->flags & CON_for)
223
{
224
if (cp->loop.f.vec)
225
{
226
sfstrclose(cp->loop.f.vec);
227
sfstrclose(cp->loop.f.tmp);
228
}
229
}
230
else if (cp->flags & CON_while)
231
{
232
if (pp->cp->loop.w.free)
233
free(pp->cp->loop.w.test);
234
}
235
pp--;
236
}
237
}
238
239
/*
240
* declare a single local variable t
241
* redefinitions on same line>0 get value 1
242
* if (flags & V_append) then old value is retained
243
* if (flags & V_scope) then value survives PUSHLOCAL/POPLOCAL
244
*/
245
246
static void
247
declare(char* t, int line, long flags)
248
{
249
register Var_t* v;
250
register Local_t* p;
251
register char* s;
252
register char* d;
253
254
if (d = strchr(t, '='))
255
*d = 0;
256
if (!(v = getvar(t)))
257
{
258
for (s = t; *s; s++)
259
if (istype(*s, C_TERMINAL))
260
error(3, "%s: invalid local variable name", t);
261
v = setvar(t, null, 0);
262
}
263
else if (!(flags & V_scope))
264
{
265
/*
266
* check for duplicate declarations
267
*/
268
269
for (p = pp->local; p; p = p->next)
270
if (v->name == p->newv.name)
271
{
272
if (d)
273
*d++ = '=';
274
else if (line && p->line == line)
275
d = "1";
276
else
277
d = null;
278
p->line = line;
279
setvar(v->name, d, 0);
280
return;
281
}
282
}
283
newlocal(p);
284
p->next = pp->local;
285
pp->local = p;
286
p->oldv = v;
287
p->newv.name = v->name;
288
p->newv.property &= ~(V_readonly|V_scope);
289
p->newv.property |= (v->property & (V_auxiliary|V_scan)) | (flags & V_scope);
290
if (!p->newv.value || (p->newv.property & V_import))
291
{
292
p->newv.value = newof(0, char, MINVALUE + 1, 0);
293
p->newv.length = MINVALUE;
294
p->newv.property &= ~V_import;
295
p->newv.property |= V_free;
296
}
297
p->bucket = hashlast(table.var);
298
p->bucket->value = (char*)&p->newv;
299
p->line = line;
300
if (d)
301
{
302
*d++ = '=';
303
setvar(v->name, d, 0);
304
}
305
else if (flags & V_append)
306
setvar(v->name, v->value, 0);
307
else
308
*p->newv.value = 0;
309
}
310
311
/*
312
* declare local variables using tmp string xp
313
* v is first expanded
314
* 2 funtion argument styles supported
315
* (formal ...) actual ...
316
* -[n] actual
317
*/
318
319
static void
320
local(Sfio_t* xp, char* v)
321
{
322
register char* t;
323
register char* a;
324
long top;
325
int argn;
326
Control_t* cp;
327
Local_t* p;
328
int argc = 0;
329
int optional = 0;
330
char* argv = 0;
331
char* formal = 0;
332
Sfio_t* ap = 0;
333
334
for (cp = pp->cp; cp > pp->block; cp--)
335
if (cp->flags & (CON_for|CON_while))
336
{
337
for (p = pp->local; p; p = p->next)
338
p->line = 0;
339
break;
340
}
341
if (t = strchr(v, '\n'))
342
*t = 0;
343
top = sfstrtell(xp);
344
expand(xp, v);
345
sfputc(xp, 0);
346
v = sfstrseek(xp, top, SEEK_SET);
347
if (t)
348
*t = '\n';
349
while (t = getarg(&v, NiL))
350
{
351
if (!ap && *t == '-')
352
{
353
ap = sfstropen();
354
if (!argc)
355
argc = 1;
356
argn = strtol(t + 1, NiL, 0);
357
}
358
else if (!ap && *t == '(')
359
{
360
ap = sfstropen();
361
argv = t + strlen(t) - 1;
362
if (*argv != ')')
363
error(3, "%s: missing ) in formal argument list", t);
364
*argv = 0;
365
argv = t + 1;
366
argc = 1;
367
argn = 0;
368
formal = getarg(&argv, NiL);
369
}
370
else
371
{
372
if (argv)
373
{
374
if (!formal)
375
error(3, "%s: only %d actual argument%s expected", t, argc - 1, argc == 2 ? null : "s");
376
if ((a = getarg(&argv, NiL)) && !optional && streq(a, "..."))
377
{
378
optional = 1;
379
if (*v)
380
*(v - 1) = ' ';
381
if (!(a = getarg(&argv, NiL)))
382
v = null;
383
}
384
argc++;
385
sfprintf(ap, "%s=%s", formal, t);
386
t = sfstruse(ap);
387
formal = a;
388
}
389
else if (argc)
390
{
391
sfprintf(ap, "%d=%s", argc++, t);
392
t = sfstruse(ap);
393
}
394
declare(t, error_info.line, 0);
395
}
396
}
397
if (argc)
398
{
399
if (formal)
400
{
401
if (!optional)
402
{
403
a = getarg(&argv, NiL);
404
if (!a || !streq(a, "..."))
405
error(3, "%s: actual argument expected", formal, argc - 1);
406
}
407
while (formal)
408
{
409
declare(formal, error_info.line, 0);
410
formal = getarg(&argv, NiL);
411
}
412
}
413
pp->argc = argc - 1;
414
while (argc <= argn)
415
{
416
sfprintf(ap, "%d", argc++);
417
declare(sfstruse(ap), error_info.line, 0);
418
}
419
sfstrclose(ap);
420
}
421
}
422
423
/*
424
* copy the local argc into internal.val
425
*/
426
427
void
428
argcount(void)
429
{
430
sfprintf(internal.val, "%d", pp->argc);
431
}
432
433
/*
434
* compute next for loop iteration variable
435
*/
436
437
static int
438
iterate(void)
439
{
440
register char* p;
441
register Var_t* v = pp->cp->loop.f.var;
442
443
if (!(p = *pp->cp->loop.f.args++))
444
return 0;
445
446
/*
447
* NOTE: this may bypass checks in setvar()
448
*/
449
450
if (!(v->property & V_import) && v->value && strlen(p) <= v->length)
451
strcpy(v->value, p);
452
else
453
{
454
if (v->property & V_free)
455
{
456
v->property &= ~V_free;
457
free(v->value);
458
}
459
v->value = p;
460
v->property |= V_import;
461
}
462
debug((-6, "assignment: lhs=`%s' rhs=`%s'", v->name, v->value));
463
return 1;
464
}
465
466
/*
467
* check for pp directives
468
*/
469
470
static void
471
directive(register char* s)
472
{
473
register char* t;
474
register int n;
475
Rule_t* r;
476
Stat_t st;
477
478
static Sfio_t* file;
479
480
while (isspace(*++s));
481
if (isdigit(*s))
482
{
483
n = 0;
484
while (isdigit(*s))
485
n = n * 10 + *s++ - '0';
486
error_info.line = n - 1;
487
while (isspace(*s))
488
s++;
489
if (*s++ == '"')
490
{
491
if (!file)
492
file = sfstropen();
493
while (*s && *s != '"')
494
sfputc(file, *s++);
495
t = sfstruse(file);
496
if (*s == '"')
497
{
498
if (!*t)
499
error_info.file = pp->name;
500
else
501
{
502
pathcanon(error_info.file = t, 0, 0);
503
state.init++;
504
r = makerule(t);
505
state.init--;
506
if (!r->time && !(r->property & P_dontcare))
507
{
508
if (stat(t, &st))
509
r->property |= P_dontcare;
510
else
511
{
512
r->time = tmxgetmtime(&st);
513
compref(r, COMP_INCLUDE);
514
}
515
}
516
}
517
}
518
}
519
}
520
else
521
{
522
for (t = s; *s && !isspace(*s); s++);
523
if (*s)
524
*s++ = 0;
525
if (streq(t, "rules"))
526
rules(s);
527
else if (!state.preprocess && strmatch(t, "assert|define|elif|else|endif|endmac|error|if|ifdef|ifndef|include|line|macdef|pragma|unassert|undef|warning"))
528
{
529
state.preprocess = 1;
530
punt(0);
531
}
532
}
533
}
534
535
/*
536
* read line from file or buffer
537
*
538
* `\<newline>' splices the current and next lead line
539
* `#...<newline>' comments (preceded by space) are stripped from files
540
*
541
* return value for file input placed in pp->ip
542
*/
543
544
static char*
545
readline(int lead)
546
{
547
register char* s;
548
register char* t;
549
register char* f;
550
register int c;
551
register int n;
552
register int q;
553
Rule_t* r;
554
int start;
555
int here;
556
int m;
557
long line;
558
Sfio_t* sps[2];
559
560
trap();
561
if (s = pp->pushback)
562
{
563
pp->pushback = 0;
564
if (pp->fp)
565
{
566
if (lead > 0 && (t = sfstrseek(pp->ip, 0, SEEK_CUR) - 1) > s && *(t - 1) == '\\')
567
{
568
sfstrseek(pp->ip, -2, SEEK_CUR);
569
line = s - sfstrbase(pp->ip);
570
goto pushback;
571
}
572
return s;
573
}
574
else if (t = pp->bp = strchr(s, '\n'))
575
{
576
if (lead > 0 && t > s && *(t - 1) == '\\')
577
*(t - 1) = *t = ' ';
578
else
579
{
580
pp->newline = 1;
581
*pp->bp = 0;
582
return s;
583
}
584
}
585
else
586
return s;
587
}
588
else
589
s = pp->bp;
590
if (pp->fp)
591
{
592
if (s = pp->stashget)
593
{
594
*s++ = '\n';
595
if (t = strchr(s, '\n'))
596
*(pp->stashget = t) = 0;
597
else
598
pp->stashget = 0;
599
return s;
600
}
601
if (pp->stashput)
602
{
603
sfstrseek(pp->ip, -1, SEEK_CUR);
604
sfputc(pp->ip, '\n');
605
}
606
else
607
sfstrseek(pp->ip, 0, SEEK_SET);
608
line = sfstrtell(pp->ip);
609
pushback:
610
do
611
{
612
trap();
613
if (r = getrule(external.makeprompt))
614
maketop(r, P_dontcare|P_foreground, NiL);
615
if (pp->prompt)
616
error(ERROR_PROMPT, lead > 0 && pp->cp == pp->block ? PS1 : PS2);
617
if (pp->fp != sfstdin || !state.coshell || !state.coshell->outstanding)
618
break;
619
sps[0] = pp->fp;
620
sps[1] = state.coshell->msgfp;
621
if ((n = sfpoll(sps, 2, -1)) <= 0)
622
continue;
623
if (sps[0] == state.coshell->msgfp || n > 1 && sps[1] == state.coshell->msgfp)
624
while (block(1));
625
} while (sps[0] != pp->fp && (n <= 1 || sps[1] != pp->fp));
626
here = pp->checkhere = 0;
627
n = q = 0;
628
for (;;)
629
{
630
switch (c = sfgetc(pp->fp))
631
{
632
case EOF:
633
eof:
634
if (q == COMMENT)
635
error(lead > 0 ? 2 : 1, "EOF in %c comment", q);
636
else if (q)
637
error(lead > 0 ? 2 : 1, "EOF in %c...%c quote starting at line %d", q, q, start);
638
else if (sfstrtell(pp->ip) > line)
639
error(lead > 0 ? 2 : 1, "file does not end with newline");
640
if (sfstrtell(pp->ip) > line)
641
{
642
sfputc(pp->ip, 0);
643
return sfstrbase(pp->ip) + line;
644
}
645
return 0;
646
case '\r':
647
if ((c = sfgetc(pp->fp)) != '\n')
648
{
649
if (c != EOF)
650
sfungetc(pp->fp, c);
651
c = '\r';
652
break;
653
}
654
/*FALLTHROUGH*/
655
case '\n':
656
newline:
657
error_info.line++;
658
if (!q || q == COMMENT)
659
{
660
t = sfstrseek(pp->ip, 0, SEEK_CUR);
661
s = sfstrbase(pp->ip) + line;
662
while (t > s && (*(t - 1) == ' ' || *(t - 1) == '\t'))
663
t--;
664
sfstrseek(pp->ip, t - sfstrbase(pp->ip), SEEK_SET);
665
sfputc(pp->ip, 0);
666
s = sfstrbase(pp->ip) + line;
667
if (*s == COMMENT)
668
{
669
directive(s);
670
*s = 0;
671
sfstrseek(pp->ip, line + 1, SEEK_SET);
672
}
673
return s;
674
}
675
if (pp->prompt)
676
error(ERROR_PROMPT, PS2);
677
break;
678
case '\\':
679
switch (c = sfgetc(pp->fp))
680
{
681
case EOF:
682
sfputc(pp->ip, '\\');
683
goto eof;
684
case '\r':
685
if ((c = sfgetc(pp->fp)) != '\n')
686
{
687
if (c != EOF)
688
sfungetc(pp->fp, c);
689
sfputc(pp->ip, '\\');
690
c = '\r';
691
break;
692
}
693
/*FALLTHROUGH*/
694
case '\n':
695
if (lead > 0)
696
{
697
error_info.line++;
698
if (pp->prompt)
699
error(ERROR_PROMPT, PS2);
700
continue;
701
}
702
pp->splice = error_info.line + 2;
703
sfungetc(pp->fp, '\n');
704
c = '\\';
705
break;
706
default:
707
sfputc(pp->ip, '\\');
708
break;
709
}
710
break;
711
case '"':
712
case '\'':
713
if (c == q)
714
q = 0;
715
else if (!q)
716
{
717
q = c;
718
start = error_info.line;
719
}
720
break;
721
case '/':
722
if (!q && (sfstrtell(pp->ip) == line || isspace(*(sfstrseek(pp->ip, 0, SEEK_CUR) - 1))))
723
switch (c = sfgetc(pp->fp))
724
{
725
case EOF:
726
sfputc(pp->ip, '/');
727
goto eof;
728
case '*':
729
start = ++error_info.line;
730
mid:
731
for (;;) switch (sfgetc(pp->fp))
732
{
733
case EOF:
734
comeof:
735
error(2, "EOF in /*...*/ comment starting at line %d", start);
736
goto end;
737
case '\n':
738
error_info.line++;
739
sfputc(pp->ip, '\n');
740
if (pp->prompt)
741
error(ERROR_PROMPT, PS2);
742
break;
743
case '/':
744
for (;;) switch (c = sfgetc(pp->fp))
745
{
746
case EOF:
747
goto comeof;
748
case '*':
749
if (error_info.line > start)
750
error(2, "/* in /*...*/ comment starting at line %d", start);
751
break;
752
case '/':
753
break;
754
default:
755
sfungetc(pp->fp, c);
756
goto mid;
757
}
758
case '*':
759
for (;;) switch (c = sfgetc(pp->fp))
760
{
761
case EOF:
762
goto comeof;
763
case '*':
764
break;
765
case '/':
766
goto end;
767
default:
768
sfungetc(pp->fp, c);
769
goto mid;
770
}
771
}
772
end:
773
error_info.line--;
774
c = ' ';
775
break;
776
default:
777
sfungetc(pp->fp, c);
778
c = '/';
779
break;
780
}
781
break;
782
case COMMENT:
783
if (!q && (q = c) && sfstrtell(pp->ip) > line && isspace(*(sfstrseek(pp->ip, 0, SEEK_CUR) - 1)))
784
for (;;)
785
switch (sfgetc(pp->fp))
786
{
787
case EOF:
788
goto eof;
789
case '\\':
790
switch (sfgetc(pp->fp))
791
{
792
case EOF:
793
goto eof;
794
case '\\':
795
sfungetc(pp->fp, '\\');
796
break;
797
case '\n':
798
if (!lead)
799
goto newline;
800
error_info.line++;
801
sfputc(pp->ip, '\n');
802
if (pp->prompt)
803
error(ERROR_PROMPT, PS2);
804
break;
805
}
806
continue;
807
case '\n':
808
goto newline;
809
}
810
break;
811
case '(':
812
case '[':
813
case '{':
814
if (!q)
815
n++;
816
break;
817
case ')':
818
case ']':
819
case '}':
820
if (!q && n)
821
n--;
822
break;
823
case '<':
824
if (!q && !n && !pp->checkhere && (m = sfstrtell(pp->ip) - line))
825
{
826
if (m == here)
827
pp->checkhere = 1;
828
else
829
here = m + 1;
830
}
831
break;
832
}
833
sfputc(pp->ip, c);
834
}
835
}
836
else if (s)
837
{
838
error_info.line++;
839
if (pp->newline)
840
{
841
pp->newline = 0;
842
*s++ = '\n';
843
}
844
if (f = strchr(s, '\n'))
845
{
846
if (lead > 0 && f > s && *(f - 1) == '\\')
847
{
848
/*
849
* NOTE: `\\n' are permanently eliminated *each pass*
850
* line counts are preserved by adding newlines
851
* after sliding the spliced segment(s)
852
*/
853
854
n = 1;
855
t = f - 1;
856
for (;;)
857
{
858
if (!(c = *++f))
859
{
860
f = 0;
861
*t = 0;
862
break;
863
}
864
else if (c != '\n')
865
*t++ = c;
866
else if (*(f - 1) != '\\')
867
{
868
f = t + 1;
869
while (n--)
870
{
871
*t++ = ' ';
872
*t++ = '\n';
873
}
874
break;
875
}
876
else
877
{
878
n++;
879
t--;
880
}
881
}
882
}
883
}
884
if (pp->bp = f)
885
{
886
*f = 0;
887
pp->newline = 1;
888
}
889
return s;
890
}
891
else
892
return 0;
893
}
894
895
/*
896
* structured flow control line input into sp
897
*
898
* lead identifies a lead line (as opposed to an action line)
899
* term is the line terminator char placed in sp
900
* 0 return on EOF
901
*/
902
903
static int
904
getline(Sfio_t* sp, int lead, int term)
905
{
906
register int c;
907
register char* s;
908
register char* t;
909
register int indent;
910
Time_t tm;
911
long n;
912
int i;
913
char* e;
914
char* lin;
915
char* tok;
916
Control_t* cp;
917
Namval_t* nv;
918
919
if (pp->here && !lead)
920
{
921
t = pp->here;
922
pp->here = 0;
923
while ((s = sfgetr(pp->fp, '\n', 1)) && !streq(s, t))
924
sfputr(sp, s, term);
925
if (!s)
926
error(3, "here document terminator \"%s\" not found", t);
927
free(t);
928
return sfstrtell(sp) != 0;
929
}
930
again:
931
while (s = lin = readline(lead))
932
{
933
indent = 0;
934
if (lead > 0 && !(pp->cp->flags & CON_skip))
935
pp->indent = SHRT_MAX;
936
while (indent <= pp->indent)
937
{
938
if (*s == '\t')
939
{
940
s++;
941
indent += state.tabstops - indent % state.tabstops;
942
}
943
else if (*s == ' ')
944
{
945
static int warned;
946
947
for (t = s; isspace(*t); t++);
948
if (!*t)
949
goto again;
950
if (!warned)
951
{
952
error(1, "<space> indentation may be non-portable");
953
warned = 1;
954
}
955
while (*s == ' ')
956
{
957
s++;
958
indent++;
959
}
960
}
961
else
962
break;
963
}
964
if (lead > 0 && indent <= pp->indent && (c = *s))
965
{
966
pp->indent = indent;
967
if (c == 'b' || c == 'c' || c == 'e' || c == 'f' || c == 'i' || c == 'l' || c == 'p' || c == 'r' || c == 's' || c == 'w')
968
{
969
for (t = s; istype(*t, C_VARIABLE2); t++);
970
if (istype(c = *t, C_SEP))
971
{
972
*t = 0;
973
i = (nv = (Namval_t*)strsearch(controls, elementsof(controls), sizeof(*controls), stracmp, s, NiL)) ? nv->value : 0;
974
for (*t = c; isspace(*t); t++);
975
c = pp->cp->flags;
976
/*UNDENT*/
977
if (i)
978
{
979
debug((-7, "%s:%d:test: `%s'", error_info.file, error_info.line, s));
980
switch (i)
981
{
982
983
case CON_if:
984
if (++pp->cp >= &constack[elementsof(constack)])
985
error(3, "if nesting too deep");
986
pp->cp->flags = CON_if;
987
if (c & CON_skip)
988
pp->cp->flags |= CON_kept | CON_skip;
989
else if (expr(sp, t))
990
pp->cp->flags |= CON_kept;
991
else
992
pp->cp->flags |= CON_skip;
993
continue;
994
995
case CON_else:
996
if (!(c & CON_if))
997
error(3, "no matching if for else");
998
if (*t != 'i' || *(t + 1) != 'f' || !isspace(*(t + 2)))
999
{
1000
if (c & CON_else)
1001
error(1, "only one else per if");
1002
if (*t)
1003
error(1, "%s: tokens after else ignored", t);
1004
pp->cp->flags |= CON_else;
1005
if (c & CON_kept)
1006
pp->cp->flags |= CON_skip;
1007
else
1008
{
1009
pp->cp->flags |= CON_kept;
1010
pp->cp->flags &= ~CON_skip;
1011
}
1012
continue;
1013
}
1014
t++;
1015
while (isspace(*++t));
1016
/*FALLTHROUGH*/
1017
1018
case CON_elif:
1019
if (!(c & CON_if))
1020
error(3, "no matching if for elif");
1021
if (c & CON_else)
1022
error(1, "elif after else");
1023
if ((c & CON_kept) || !expr(sp, t))
1024
pp->cp->flags |= CON_skip;
1025
else
1026
{
1027
pp->cp->flags |= CON_kept;
1028
pp->cp->flags &= ~CON_skip;
1029
}
1030
continue;
1031
1032
case CON_end:
1033
if (pp->cp <= pp->block)
1034
error(3, "unmatched end");
1035
if (*t)
1036
error(1, "%s: tokens after end ignored", t);
1037
if (c & CON_eval)
1038
pp->eval--;
1039
else if (!(c & CON_skip) || (c & (CON_for | CON_while)) && !(c & CON_kept))
1040
{
1041
pp->cp->flags &= ~(CON_kept | CON_skip);
1042
if ((c & CON_while) && expr(sp, pp->cp->loop.w.test) || (c & CON_for) && iterate())
1043
{
1044
if (pp->newline)
1045
{
1046
pp->newline = 0;
1047
*pp->bp = '\n';
1048
}
1049
if (pp->fp)
1050
{
1051
if (pp->stashget)
1052
*pp->stashget = '\n';
1053
pp->stashget = sfstrbase(pp->ip) + pp->cp->body.offset;
1054
}
1055
else
1056
pp->bp = pp->cp->body.buffer;
1057
error_info.line = pp->cp->line;
1058
continue;
1059
}
1060
}
1061
if (c & CON_for)
1062
{
1063
if (pp->cp->loop.f.vec)
1064
{
1065
sfstrclose(pp->cp->loop.f.vec);
1066
sfstrclose(pp->cp->loop.f.tmp);
1067
}
1068
}
1069
if (c & CON_while)
1070
{
1071
if (pp->cp->loop.w.free)
1072
free(pp->cp->loop.w.test);
1073
}
1074
if (c & CON_stash)
1075
pp->stashput = 0;
1076
pp->cp--;
1077
continue;
1078
1079
case CON_for:
1080
if (++pp->cp >= &constack[elementsof(constack)])
1081
error(3, "for nesting too deep");
1082
pp->cp->flags = CON_for;
1083
pp->cp->loop.f.vec = 0;
1084
if (c & CON_skip)
1085
pp->cp->flags |= CON_kept | CON_skip;
1086
else
1087
{
1088
Sfio_t* tp;
1089
1090
pp->cp->loop.f.tmp = tp = sfstropen();
1091
expand(tp, t);
1092
tok = sfstruse(tp);
1093
if (!(s = getarg(&tok, NiL)))
1094
error(3, "for loop variable omitted");
1095
pp->cp->loop.f.vec = tp = sfstropen();
1096
do putptr(tp, t = getarg(&tok, NiL)); while (t);
1097
if (*(pp->cp->loop.f.args = (char**)sfstrseek(tp, 0, SEEK_SET)))
1098
{
1099
pp->cp->loop.f.var = setvar(s, null, 0);
1100
if (!iterate())
1101
pp->cp->flags |= CON_kept | CON_skip;
1102
else
1103
{
1104
if (pp->fp)
1105
{
1106
if (!pp->stashput)
1107
{
1108
pp->stashput = 1;
1109
pp->cp->flags |= CON_stash;
1110
sfstrseek(pp->ip, 0, SEEK_SET);
1111
sfputc(pp->ip, 0);
1112
}
1113
pp->cp->body.offset = pp->stashget ? (pp->stashget - sfstrbase(pp->ip)) : (sfstrtell(pp->ip) - 1);
1114
}
1115
else if (!pp->bp)
1116
error(3, "for loop body expected");
1117
else
1118
pp->cp->body.buffer = pp->bp + 1;
1119
pp->cp->line = error_info.line;
1120
}
1121
}
1122
else
1123
pp->cp->flags |= CON_kept | CON_skip;
1124
}
1125
continue;
1126
1127
case CON_while:
1128
if (++pp->cp >= &constack[elementsof(constack)])
1129
error(3, "while nesting too deep");
1130
pp->cp->flags = CON_while;
1131
pp->cp->loop.w.free = 0;
1132
if ((c & CON_skip) || !expr(sp, t))
1133
pp->cp->flags |= CON_kept | CON_skip;
1134
else
1135
{
1136
pp->cp->loop.w.test = t;
1137
if (pp->fp)
1138
{
1139
if (!pp->stashput)
1140
{
1141
pp->stashput = 1;
1142
pp->cp->flags |= CON_stash;
1143
sfstrseek(pp->ip, 0, SEEK_SET);
1144
sfputc(pp->ip, 0);
1145
pp->cp->loop.w.test = strdup(t);
1146
pp->cp->loop.w.free = 1;
1147
}
1148
pp->cp->body.offset = pp->stashget ? (pp->stashget - sfstrbase(pp->ip)) : (sfstrtell(pp->ip) - 1);
1149
}
1150
else if (!pp->bp)
1151
error(3, "while loop body expected");
1152
else
1153
pp->cp->body.buffer = pp->bp + 1;
1154
pp->cp->line = error_info.line;
1155
}
1156
continue;
1157
1158
case CON_break:
1159
case CON_continue:
1160
if (!(pp->cp->flags & CON_skip))
1161
{
1162
c = *t ? expr(sp, t) : 1;
1163
for (cp = pp->cp; cp > pp->block; cp--)
1164
{
1165
if (cp <= pp->block)
1166
error(3, "%s outside of loop", s);
1167
cp->flags |= CON_skip | CON_kept;
1168
if ((cp->flags & (CON_for | CON_while)) && --c <= 0)
1169
{
1170
if (i == CON_continue)
1171
cp->flags &= ~CON_kept;
1172
break;
1173
}
1174
}
1175
}
1176
continue;
1177
1178
case CON_return:
1179
if (!(pp->cp->flags & CON_skip))
1180
{
1181
if (state.frame->target->property & P_functional)
1182
{
1183
n = sfstrtell(sp);
1184
expand(sp, t);
1185
s = sfstrbase(sp) + n;
1186
t = sfstrseek(sp, 0, SEEK_CUR);
1187
while (t > s && isspace(*(t - 1)))
1188
t--;
1189
sfstrseek(sp, t - sfstrbase(sp), SEEK_SET);
1190
sfputc(sp, 0);
1191
setvar(state.frame->target->name, sfstrseek(sp, n, SEEK_SET), 0);
1192
debug((-5, "%s returns `%s'", state.frame->target->name, sfstrseek(sp, 0, SEEK_CUR)));
1193
}
1194
else if (*t)
1195
{
1196
if ((tm = timenum(t, &e)) != TMX_NOTIME && *e)
1197
{
1198
if ((n = expr(sp, t)) == -1)
1199
tm = TMX_NOTIME;
1200
else
1201
tm = tmxsns(n, 0);
1202
}
1203
if (tm == TMX_NOTIME)
1204
{
1205
pp->status = FAILED;
1206
debug((-5, "return fail"));
1207
}
1208
else if (tm)
1209
{
1210
pp->status = TOUCH;
1211
internal.internal->time = tm;
1212
debug((-5, "return [%s]", timestr(internal.internal->time)));
1213
}
1214
else
1215
{
1216
pp->status = EXISTS;
1217
debug((-5, "return no update"));
1218
}
1219
}
1220
else
1221
debug((-5, "return normal"));
1222
for (cp = pp->cp; cp >= pp->block; cp--)
1223
cp->flags |= CON_skip | CON_kept;
1224
}
1225
continue;
1226
1227
case CON_eval:
1228
if (++pp->cp >= &constack[elementsof(constack)])
1229
error(3, "eval nesting too deep");
1230
pp->cp->flags = CON_eval | (c & (CON_kept | CON_skip));
1231
pp->eval++;
1232
continue;
1233
1234
case CON_rules:
1235
if (!(pp->cp->flags & CON_skip))
1236
rules(t);
1237
continue;
1238
1239
case CON_let:
1240
if (!(pp->cp->flags & CON_skip))
1241
expr(sp, t);
1242
continue;
1243
1244
case CON_local:
1245
if (!(pp->cp->flags & CON_skip))
1246
local(sp, t);
1247
continue;
1248
1249
case CON_error:
1250
if (!(pp->cp->flags & CON_skip))
1251
{
1252
n = sfstrtell(sp);
1253
expand(sp, t);
1254
sfputc(sp, 0);
1255
i = strtol(sfstrseek(sp, n, SEEK_SET), &tok, 0);
1256
for (t = tok; isspace(*t); t++);
1257
c = error_info.line;
1258
if (i > 0 && !(i & 040))
1259
error_info.line = 0;
1260
error(i, "%s", t);
1261
error_info.line = c;
1262
}
1263
continue;
1264
1265
case CON_exit:
1266
if (!(pp->cp->flags & CON_skip))
1267
{
1268
n = sfstrtell(sp);
1269
expand(sp, t);
1270
sfputc(sp, 0);
1271
i = strtol(sfstrseek(sp, n, SEEK_SET), &tok, 0);
1272
finish(i);
1273
}
1274
continue;
1275
1276
case CON_print:
1277
case CON_read:
1278
if (!(pp->cp->flags & CON_skip))
1279
{
1280
int d;
1281
int m;
1282
int x;
1283
char* a;
1284
char* f;
1285
1286
n = sfstrtell(sp);
1287
expand(sp, t);
1288
sfputc(sp, 0);
1289
a = sfstrseek(sp, n, SEEK_SET);
1290
d = i == CON_print;
1291
f = 0;
1292
n = '\n';
1293
/*UNDENT...*/
1294
1295
for (;;)
1296
{
1297
for (t = a; *t == ' '; t++);
1298
if ((x = *t) != '-' && x != '+')
1299
break;
1300
a = t;
1301
t = getarg(&a, NiL) + 1;
1302
if (*(t - 1) == *t && !*(t + 1))
1303
{
1304
for (t = a; *t == ' '; t++);
1305
break;
1306
}
1307
for (;;)
1308
{
1309
switch (m = *t++)
1310
{
1311
case 0:
1312
break;
1313
case 'f':
1314
if (*t)
1315
f = t;
1316
else if (!(f = getarg(&a, NiL)))
1317
error(3, "-f: format argument expected");
1318
break;
1319
case 'i':
1320
case 'o':
1321
case 'p':
1322
if (!*t && !(t = getarg(&a, NiL)))
1323
{
1324
error(3, "-%c: file argument expected", m);
1325
t = "-";
1326
}
1327
if (state.io[d])
1328
{
1329
if (state.io[d] != sfstdin && state.io[d] != sfstdout && state.io[d] != sfstderr)
1330
sfclose(state.io[d]);
1331
state.io[d] = 0;
1332
}
1333
if (!streq(t, "-"))
1334
switch (m)
1335
{
1336
case 'i':
1337
if (!(state.io[d] = sfopen(NiL, t, x == '+' ? "rwe" : "re")))
1338
error(ERROR_SYSTEM|2, "%s: cannot read", t);
1339
break;
1340
case 'o':
1341
if (!(state.io[d] = sfopen(NiL, t, x == '+' ? "ae" : "we")))
1342
error(ERROR_SYSTEM|2, "%s: cannot write", t);
1343
break;
1344
case 'p':
1345
if (!(state.io[d] = sfpopen(NiL, t, "rw")))
1346
error(ERROR_SYSTEM|2, "%s: cannot connect to coprocess", t);
1347
else
1348
sfdcslow(state.io[d]);
1349
break;
1350
}
1351
if (!state.io[d])
1352
switch (d)
1353
{
1354
case 0:
1355
state.io[d] = sfstdin;
1356
break;
1357
case 1:
1358
state.io[d] = sfstdout;
1359
break;
1360
case 2:
1361
state.io[d] = sfstderr;
1362
break;
1363
}
1364
else if (m != 'p')
1365
sfsetbuf(state.io[d], NiL, 0);
1366
break;
1367
case 'n':
1368
n = -1;
1369
continue;
1370
case 'u':
1371
if (!*t && !(t = getarg(&a, NiL)))
1372
error(3, "-u: unit argument expected");
1373
switch (c = *t++)
1374
{
1375
case 'm':
1376
if ((state.io[d = elementsof(state.io) - 1] = state.mam.out) && *state.mam.label)
1377
sfputr(state.io[d], state.mam.label, -1);
1378
break;
1379
case '0': case '1': case '2': case '3': case '4':
1380
case '5': case '6': case '7': case '8': case '9':
1381
d = c - '0';
1382
break;
1383
default:
1384
error(2, "-u: unit [0-9m] expected");
1385
break;
1386
}
1387
continue;
1388
default:
1389
error(3, "-%c: unknown option", *(t - 1));
1390
continue;
1391
}
1392
break;
1393
}
1394
}
1395
1396
/*...INDENT*/
1397
if (i == CON_print)
1398
{
1399
if (state.io[d] && (sfset(state.io[d], 0, 0) & SF_WRITE))
1400
{
1401
if (f)
1402
strprintf(state.io[d], f, t, 0, n);
1403
else
1404
sfputr(state.io[d], t, n);
1405
}
1406
else if (*t || n != -1)
1407
error(2, "unit %d not open for writing", d);
1408
}
1409
else if (n != -1 || *t)
1410
{
1411
if (state.io[d] && (sfset(state.io[d], 0, 0) & SF_READ))
1412
{
1413
if (!*(a = t) || !(t = getarg(&a, NiL)) || getarg(&a, NiL))
1414
error(2, "one variable argument expected");
1415
else
1416
{
1417
if (f)
1418
error(1, "read format ignored");
1419
sfset(state.io[d], SF_IOINTR, 1);
1420
if (!(f = sfgetr(state.io[d], '\n', 1)))
1421
f = null;
1422
setvar(t, f, 0);
1423
}
1424
}
1425
else
1426
error(2, "unit %d not open for reading", d);
1427
}
1428
}
1429
continue;
1430
1431
case CON_set:
1432
if (!(pp->cp->flags & CON_skip))
1433
{
1434
n = sfstrtell(sp);
1435
expand(sp, t);
1436
sfputc(sp, 0);
1437
set(sfstrseek(sp, n, SEEK_SET), 1, pp->scoped);
1438
}
1439
continue;
1440
}
1441
}
1442
/*INDENT*/
1443
}
1444
}
1445
}
1446
#if DEBUG
1447
if (pp->cp->flags & CON_skip)
1448
debug((-8, "%s:%d:skip: `%s'", error_info.file, error_info.line, s));
1449
else
1450
debug((-7, "%s:%d:data: `%s'", error_info.file, error_info.line, s));
1451
#endif
1452
if (!(pp->cp->flags & CON_skip))
1453
{
1454
for (t = s; isspace(*t); t++);
1455
if (*t)
1456
{
1457
if (!lead && indent <= pp->indent)
1458
{
1459
if (pp->newline)
1460
{
1461
pp->newline = 0;
1462
*pp->bp = '\n';
1463
}
1464
pp->pushback = lin;
1465
return 0;
1466
}
1467
break;
1468
}
1469
else if (!lead && pp->fp == sfstdin)
1470
return 0;
1471
else if (pp->splice == error_info.line)
1472
break;
1473
else if (!lead)
1474
{
1475
sfputr(sp, s, term);
1476
return 1;
1477
}
1478
}
1479
}
1480
if (!s)
1481
return 0;
1482
switch (i = pp->eval)
1483
{
1484
case 0:
1485
sfputr(sp, s, term);
1486
break;
1487
case 1:
1488
expand(sp, s);
1489
sfputc(sp, term);
1490
break;
1491
default:
1492
{
1493
Sfio_t* tp;
1494
Sfio_t* xp;
1495
1496
tp = sfstropen();
1497
for (;;)
1498
{
1499
xp = (i & 1) ? sp : tp;
1500
expand(xp, s);
1501
if (--i <= 0)
1502
break;
1503
s = sfstruse(xp);
1504
}
1505
sfstrclose(tp);
1506
sfputc(sp, term);
1507
}
1508
break;
1509
}
1510
return 1;
1511
}
1512
1513
/*
1514
* makefile statement parser
1515
*
1516
* the statement grammar is
1517
*
1518
* <lhs> <op> <rhs> <act>
1519
*
1520
* <lhs>, <rhs> and <act> are placed in sp
1521
* <op> determines which components are expanded when read
1522
*
1523
* <op> <lhs> <rhs> <act>
1524
* -----------------------------
1525
* = 0 0 -
1526
* := 1 1 -
1527
* += 1 1 -
1528
* : 1 1 0
1529
* :op: 0 0 0
1530
*
1531
* an action <act> is not expanded when read
1532
* actions are indented by a number of <tab> chars
1533
* the indent tabs are stripped from each line in the action
1534
* the first line not indented by this amount terminates the action
1535
* ideally only '\t' should be used although ' ' are ok using state.tabstops
1536
* the statement operator flags OP_* are returned
1537
*/
1538
1539
static int
1540
statement(Sfio_t* sp, char** lhs, Rule_t** opr, char** rhs, char** act)
1541
{
1542
register int c;
1543
register char* s;
1544
register char* t;
1545
char* b;
1546
char* p;
1547
char* brace = 0;
1548
char* ecarb = 0;
1549
int item = 0;
1550
int op = 0;
1551
int nest = 0;
1552
int paren = 0;
1553
int quote = 0;
1554
long rhs_pos = -1;
1555
long act_pos = -1;
1556
long lin_pos;
1557
1558
if (!getline(sp, 1, 0))
1559
return op;
1560
*opr = 0;
1561
b = s = sfstrbase(sp);
1562
while (c = *s++)
1563
{
1564
if (c == '\\')
1565
{
1566
if (*s)
1567
s++;
1568
}
1569
else if (c == quote)
1570
quote = 0;
1571
else if (c == '"' || c == '\'')
1572
quote = c;
1573
else if (!quote)
1574
{
1575
if (brace)
1576
{
1577
if (c == '{')
1578
nest++;
1579
else if (c == '}' && !--nest)
1580
{
1581
for (p = s; isspace(*p); p++);
1582
if (*p || brace > b && *(brace - 1) == '$')
1583
{
1584
brace = 0;
1585
continue;
1586
}
1587
ecarb = s - 1;
1588
}
1589
}
1590
else if (c == '(')
1591
paren++;
1592
else if (c == ')' && !paren--)
1593
error(3, "to many )'s");
1594
else if (!paren)
1595
{
1596
if (c == '{')
1597
{
1598
brace = s - 1;
1599
nest++;
1600
}
1601
else if (c == '}')
1602
error(3, "unbalanced {...}");
1603
else if (c == ':')
1604
{
1605
if (item < 2 && *s == '=')
1606
{
1607
t = s + 1;
1608
op = OP_ASSIGN|OP_EXPAND;
1609
break;
1610
}
1611
t = s;
1612
if (istype(*t, C_ID1))
1613
while (istype(*++t, C_ID2));
1614
if (*t++ == ':')
1615
{
1616
c = *t;
1617
*t = 0;
1618
if (!(*opr = getrule(s - 1)) || !((*opr)->property & P_operator))
1619
{
1620
Sfio_t* tmp;
1621
1622
tmp = sfstropen();
1623
*(t - 1) = 0;
1624
sfprintf(tmp, "%s%s", s, external.source);
1625
*(t - 1) = ':';
1626
op = readfile(sfstruse(tmp), COMP_INCLUDE|COMP_DONTCARE, NiL);
1627
sfstrclose(tmp);
1628
if (!op || !(*opr = getrule(s - 1)) || !((*opr)->property & P_operator))
1629
{
1630
*opr = internal.op;
1631
error(1, "operator %s not defined", s - 1);
1632
}
1633
}
1634
*t = c;
1635
op = OP_ASSERT|OP_ACTION|OP_EXPAND;
1636
if (((*opr)->property & P_ignore))
1637
op &= ~OP_EXPAND;
1638
break;
1639
}
1640
t = s;
1641
op = OP_ASSERT|OP_ACTION|OP_EXPAND;
1642
break;
1643
}
1644
else if (item < 2)
1645
{
1646
if (isspace(c))
1647
{
1648
item++;
1649
while (isspace(*s))
1650
s++;
1651
if ((c = *s) != ':' && c != '+' && c != '&' && c != '=')
1652
item++;
1653
}
1654
else if (c == '+')
1655
{
1656
if (*s == '=')
1657
{
1658
t = s + 1;
1659
op = OP_ASSIGN|OP_APPEND|OP_EXPAND;
1660
break;
1661
}
1662
}
1663
else if (c == '&')
1664
{
1665
if (*s == '=')
1666
{
1667
t = s + 1;
1668
op = OP_ASSIGN|OP_EXPAND|OP_AUXILIARY;
1669
break;
1670
}
1671
}
1672
else if (c == '=')
1673
{
1674
if (*s == '=')
1675
{
1676
t = s + 1;
1677
op = OP_ASSIGN|OP_STATE;
1678
break;
1679
}
1680
t = s;
1681
op = OP_ASSIGN;
1682
break;
1683
}
1684
}
1685
}
1686
}
1687
}
1688
if (quote)
1689
error(1, "missing closing %c quote", quote);
1690
else if (paren)
1691
error(1, "%d closing )%s missing from line", paren, paren == 1 ? null : "'s");
1692
if (op)
1693
{
1694
if (op & OP_EXPAND)
1695
{
1696
Sfio_t* tmp;
1697
1698
tmp = sfstropen();
1699
*(s - 1) = 0;
1700
sfputr(tmp, sfstrbase(sp), 0);
1701
rhs_pos = sfstrtell(tmp);
1702
sfputr(tmp, t, 0);
1703
sfstrseek(sp, 0, SEEK_SET);
1704
expand(sp, sfstrseek(tmp, 0, SEEK_SET));
1705
sfputc(sp, 0);
1706
sfstrseek(tmp, rhs_pos, SEEK_SET);
1707
rhs_pos = sfstrtell(sp);
1708
expand(sp, sfstrseek(tmp, 0, SEEK_CUR));
1709
sfputc(sp, 0);
1710
sfstrclose(tmp);
1711
s = t = sfstrbase(sp) + rhs_pos;
1712
p = sfstrseek(sp, 0, SEEK_CUR) - 1;
1713
}
1714
else
1715
p = t + strlen(t);
1716
while (p > t && isspace(*(p - 1)))
1717
p--;
1718
*p = 0;
1719
while (isspace(*t))
1720
t++;
1721
rhs_pos = t - sfstrbase(sp);
1722
t = sfstrbase(sp);
1723
for (s--; s > t && isspace(*(s - 1)); s--);
1724
*s = 0;
1725
}
1726
else
1727
{
1728
op = OP_EMPTY;
1729
p = s - 1;
1730
s = sfstrbase(sp);
1731
while (p > s && isspace(*(p - 1)))
1732
p--;
1733
*p = 0;
1734
}
1735
if (brace)
1736
{
1737
for (t = brace; t > s && isspace(*(t - 1)); t--);
1738
*t = 0;
1739
if (ecarb)
1740
{
1741
*ecarb = 0;
1742
nest = 0;
1743
}
1744
if (p > ++brace)
1745
*p++ = '\n';
1746
for (;;)
1747
{
1748
if (!*brace)
1749
{
1750
*brace = ' ';
1751
*(brace + 1) = 0;
1752
break;
1753
}
1754
else if (!isspace(*brace) || *brace == '\n')
1755
break;
1756
brace++;
1757
}
1758
act_pos = brace - sfstrbase(sp);
1759
sfstrseek(sp, p - sfstrbase(sp), SEEK_SET);
1760
quote = 0;
1761
while (nest)
1762
{
1763
lin_pos = sfstrtell(sp);
1764
if (!getline(sp, -1, '\n'))
1765
{
1766
error(2, "unbalanced {...} action");
1767
break;
1768
}
1769
s = sfstrbase(sp) + lin_pos;
1770
t = sfstrseek(sp, 0, SEEK_CUR);
1771
while (s < t)
1772
{
1773
if ((c = *s++) == '\\')
1774
{
1775
if (s < t)
1776
s++;
1777
}
1778
else if (c == quote)
1779
quote = 0;
1780
else if (c == '"' || c == '\'')
1781
quote = c;
1782
else if (!quote)
1783
{
1784
if (c == '{')
1785
nest++;
1786
else if (c == '}' && !--nest)
1787
{
1788
p = s - 1;
1789
while (s < t && isspace(*s))
1790
s++;
1791
if (s < t)
1792
error(2, "tokens after closing } ignored");
1793
t = sfstrbase(sp) + act_pos;
1794
while (p > t && isspace(*(p - 1)))
1795
p--;
1796
*p = 0;
1797
if (!*t)
1798
act_pos = -1;
1799
break;
1800
}
1801
}
1802
}
1803
}
1804
}
1805
else if (op & OP_ACTION)
1806
{
1807
if (pp->checkhere)
1808
{
1809
t = b = sfstrbase(sp) + rhs_pos;
1810
nest = quote = 0;
1811
for (;;)
1812
{
1813
switch (*t++)
1814
{
1815
case 0:
1816
break;
1817
case '"':
1818
case '\'':
1819
if (*(t - 1) == quote)
1820
quote = 0;
1821
else if (!quote)
1822
quote = *(t - 1);
1823
continue;
1824
case '(':
1825
case '[':
1826
case '{':
1827
if (!quote)
1828
nest++;
1829
continue;
1830
case ')':
1831
case ']':
1832
case '}':
1833
if (!quote)
1834
nest--;
1835
continue;
1836
case '<':
1837
if (!nest && !quote && *t == '<')
1838
{
1839
s = t - 1;
1840
while (isspace(*++t));
1841
if (*t)
1842
{
1843
p = t;
1844
while (*++t)
1845
if (isspace(*t))
1846
{
1847
*t = 0;
1848
break;
1849
}
1850
pp->here = strdup(p);
1851
while (--s >= b && isspace(*s));
1852
*(s + 1) = 0;
1853
}
1854
break;
1855
}
1856
continue;
1857
default:
1858
continue;
1859
}
1860
break;
1861
}
1862
if (!*b)
1863
rhs_pos = -1;
1864
}
1865
act_pos = ++p - sfstrbase(sp);
1866
sfstrseek(sp, act_pos, SEEK_SET);
1867
while (getline(sp, 0, '\n'));
1868
t = sfstrbase(sp) + act_pos;
1869
s = sfstrseek(sp, 0, SEEK_CUR);
1870
for (;;)
1871
{
1872
if (s <= t)
1873
{
1874
act_pos = -1;
1875
break;
1876
}
1877
if (*--s != '\n')
1878
{
1879
*(s + 1) = 0;
1880
break;
1881
}
1882
}
1883
}
1884
*lhs = sfstrseek(sp, 0, SEEK_SET);
1885
*rhs = (rhs_pos >= 0) ? sfstrbase(sp) + rhs_pos : null;
1886
*act = (act_pos >= 0) ? sfstrbase(sp) + act_pos : null;
1887
return op;
1888
}
1889
1890
static const Namval_t nametypes[] =
1891
{
1892
"altstate", NAME_altstate,
1893
"assignment", NAME_assignment,
1894
"context", NAME_context,
1895
"dynamic", NAME_dynamic,
1896
"glob", NAME_glob,
1897
"identifier", NAME_identifier,
1898
"intvar", NAME_intvar,
1899
"option", NAME_option,
1900
"path", NAME_path,
1901
"staterule", NAME_staterule,
1902
"statevar", NAME_statevar,
1903
"variable", NAME_variable,
1904
};
1905
1906
#if DEBUG
1907
1908
static void
1909
fds(int details)
1910
{
1911
char* m;
1912
char* s;
1913
char* x;
1914
int i;
1915
int flags;
1916
int open_max;
1917
struct stat st;
1918
1919
if ((open_max = (int)strtol(astconf("OPEN_MAX", NiL, NiL), NiL, 0)) <= 0)
1920
open_max = OPEN_MAX;
1921
for (i = 0; i <= open_max; i++)
1922
{
1923
if (fstat(i, &st))
1924
{
1925
/* not open */
1926
continue;
1927
}
1928
if (!details)
1929
{
1930
sfprintf(sfstdout, "%d\n", i);
1931
continue;
1932
}
1933
if ((flags = fcntl(i, F_GETFL, (char*)0)) == -1)
1934
m = "--";
1935
else
1936
switch (flags & (O_RDONLY|O_WRONLY|O_RDWR))
1937
{
1938
case O_RDONLY:
1939
m = "r-";
1940
break;
1941
case O_WRONLY:
1942
m = "-w";
1943
break;
1944
case O_RDWR:
1945
m = "rw";
1946
break;
1947
default:
1948
m = "??";
1949
break;
1950
}
1951
x = (fcntl(i, F_GETFD, (char*)0) > 0) ? "x" : "-";
1952
if (isatty(i) && (s = ttyname(i)))
1953
{
1954
sfprintf(sfstdout, "%02d %s%s %s %s\n", i, m, x, fmtmode(st.st_mode, 0), s);
1955
continue;
1956
}
1957
#if defined(S_IFSOCK) && 0
1958
addrlen = sizeof(addr);
1959
memset(&addr, 0, addrlen);
1960
if (!getsockname(i, (struct sockaddr*)&addr, (void*)&addrlen))
1961
{
1962
type = 0;
1963
prot = 0;
1964
#ifdef SO_TYPE
1965
len = sizeof(type);
1966
if (getsockopt(i, SOL_SOCKET, SO_TYPE, (void*)&type, (void*)&len))
1967
type = -1;
1968
#endif
1969
#ifdef SO_PROTOTYPE
1970
len = sizeof(prot);
1971
if (getsockopt(i, SOL_SOCKET, SO_PROTOTYPE, (void*)&prot, (void*)&len))
1972
prot = -1;
1973
#endif
1974
if (!st.st_mode)
1975
st.st_mode = S_IFSOCK|S_IRUSR|S_IWUSR;
1976
s = 0;
1977
switch (type)
1978
{
1979
case SOCK_DGRAM:
1980
switch (addr.sin_family)
1981
{
1982
case AF_INET:
1983
#ifdef AF_INET6
1984
case AF_INET6:
1985
#endif
1986
s = "udp";
1987
break;
1988
}
1989
break;
1990
case SOCK_STREAM:
1991
switch (addr.sin_family)
1992
{
1993
case AF_INET:
1994
#ifdef AF_INET6
1995
case AF_INET6:
1996
#endif
1997
#ifdef IPPROTO_SCTP
1998
if (prot == IPPROTO_SCTP)
1999
s = "sctp";
2000
else
2001
#endif
2002
s = "tcp";
2003
break;
2004
}
2005
break;
2006
#ifdef SOCK_RAW
2007
case SOCK_RAW:
2008
s = "raw";
2009
break;
2010
#endif
2011
#ifdef SOCK_RDM
2012
case SOCK_RDM:
2013
s = "rdm";
2014
break;
2015
#endif
2016
#ifdef SOCK_SEQPACKET
2017
case SOCK_SEQPACKET:
2018
s = "seqpacket";
2019
break;
2020
#endif
2021
}
2022
if (!s)
2023
{
2024
for (type = 0; family[type].name && family[type].value != addr.sin_family; type++);
2025
if (!(s = (char*)family[type].name))
2026
sfsprintf(s = num, sizeof(num), "family.%d", addr.sin_family);
2027
}
2028
port = 0;
2029
#ifdef INET6_ADDRSTRLEN
2030
if (a = (char*)inet_ntop(addr.sin_family, &addr.sin_addr, nam, sizeof(nam)))
2031
port = ntohs(addr.sin_port);
2032
else
2033
#endif
2034
if (addr.sin_family == AF_INET)
2035
{
2036
a = inet_ntoa(addr.sin_addr);
2037
port = ntohs(addr.sin_port);
2038
}
2039
else
2040
{
2041
a = fam;
2042
e = (b = (unsigned char*)&addr) + addrlen;
2043
while (b < e && a < &fam[sizeof(fam)-1])
2044
a += sfsprintf(a, &fam[sizeof(fam)] - a - 1, ".%d", *b++);
2045
a = a == fam ? "0" : fam + 1;
2046
}
2047
if (port)
2048
sfprintf(sfstdout, "%02d %s%s %s /dev/%s/%s/%d\n", i, m, x, fmtmode(st.st_mode, 0), s, a, port);
2049
else
2050
sfprintf(sfstdout, "%02d %s%s %s /dev/%s/%s\n", i, m, x, fmtmode(st.st_mode, 0), s, a);
2051
continue;
2052
}
2053
#endif
2054
sfprintf(sfstdout, "%02d %s%s %s /dev/inode/%u/%u\n", i, m, x, fmtmode(st.st_mode, 0), st.st_dev, st.st_ino);
2055
}
2056
}
2057
2058
#endif
2059
2060
/*
2061
* parse a basic assertion statement
2062
*/
2063
2064
static void
2065
assertion(char* lhs, Rule_t* opr, char* rhs, char* act, int op)
2066
{
2067
register char* s;
2068
register Rule_t* r;
2069
register List_t* p;
2070
register List_t* q;
2071
int c;
2072
int i;
2073
int n;
2074
int isactive;
2075
Flags_t jointproperty;
2076
Rule_t* x;
2077
Rule_t* joint;
2078
Var_t* v;
2079
List_t* jointail;
2080
List_t* prereqs;
2081
char* name;
2082
struct /* prereq attributes */
2083
{
2084
Rule_t rule; /* rule attributes */
2085
int op; /* assertion op */
2086
} *att, clr, set;
2087
2088
if (opr)
2089
{
2090
debug((-6, "operator: lhs=`%s' %s rhs=`%s' act=`%-.1024s'", lhs, opr->name, rhs, act));
2091
apply(opr, lhs, rhs, act, CO_ALWAYS|CO_LOCAL|CO_URGENT);
2092
return;
2093
}
2094
if (internal.assert_p->prereqs && (opr = associate(internal.assert_p, NiL, lhs, NiL)) && opr->prereqs && (opr = opr->prereqs->rule) && (opr->property & P_operator) && !opr->uname)
2095
{
2096
s = opr->uname = opr->name;
2097
opr->name = lhs;
2098
apply(opr, lhs, rhs, act, CO_ALWAYS|CO_LOCAL|CO_URGENT);
2099
opr->name = s;
2100
opr->uname = 0;
2101
return;
2102
}
2103
debug((-6, "assertion: lhs=`%s' rhs=`%-.1024s' act=`%-.1024s'", lhs, rhs, act));
2104
2105
/*
2106
* special check for internal.query
2107
*/
2108
2109
if (getrule(lhs) == internal.query)
2110
{
2111
c = 0;
2112
if (!(s = getarg(&rhs, NiL)))
2113
interpreter(NiL);
2114
else if (*s == '-' && !*(s + 1))
2115
while (s = getarg(&rhs, NiL))
2116
{
2117
if (streq(s, "blocked"))
2118
{
2119
#if DEBUG
2120
c = 1;
2121
error(0, null);
2122
dumpjobs(2, JOB_blocked);
2123
#else
2124
error(2, "%s: implemented in DEBUG==1 version", s);
2125
#endif
2126
}
2127
else if (streq(s, "buckets"))
2128
{
2129
c = 0;
2130
hashdump(NiL, HASH_BUCKET);
2131
}
2132
else if (streq(s, "fds"))
2133
{
2134
#if DEBUG
2135
fds(1);
2136
c = 0;
2137
#else
2138
error(2, "%s: implemented in DEBUG==1 version", s);
2139
#endif
2140
}
2141
else if (streq(s, "hash"))
2142
{
2143
c = 0;
2144
hashdump(NiL, 0);
2145
}
2146
else if (streq(s, "jobs"))
2147
{
2148
#if DEBUG
2149
c = 1;
2150
error(0, null);
2151
dumpjobs(2, JOB_status);
2152
#else
2153
error(2, "%s: implemented in DEBUG==1 version", s);
2154
#endif
2155
}
2156
else if (streq(s, "nametype"))
2157
{
2158
while (s = getarg(&rhs, NiL))
2159
{
2160
n = nametype(s, NiL);
2161
sfprintf(sfstdout, "%16s", s);
2162
for (i = 0; i < elementsof(nametypes); i++)
2163
if (n & nametypes[i].value)
2164
sfprintf(sfstdout, " %s", nametypes[i].name);
2165
sfputc(sfstdout, '\n');
2166
}
2167
break;
2168
}
2169
else if (streq(s, "rules"))
2170
{
2171
c = 1;
2172
state.ruledump = 1;
2173
dump(sfstderr, 0);
2174
state.ruledump = 0;
2175
}
2176
else if (streq(s, "stack"))
2177
{
2178
Parseinfo_t* sp = pp;
2179
Local_t* lp;
2180
2181
c = 1;
2182
while (--sp > &parsestack[0])
2183
{
2184
sfprintf(sfstderr, "\n%s:\n", sp->name);
2185
for (lp = sp->local; lp; lp = lp->next)
2186
sfprintf(sfstderr, " %15s=%s [%s]\n", lp->oldv->name, lp->newv.value, lp->oldv->value);
2187
}
2188
}
2189
else if (streq(s, "variables"))
2190
{
2191
c = 1;
2192
state.vardump = 1;
2193
dump(sfstderr, 0);
2194
state.vardump = 0;
2195
}
2196
else if (streq(s, "view"))
2197
{
2198
if (state.maxview)
2199
{
2200
sfprintf(sfstderr, "\n");
2201
for (c = 0; c <= state.maxview; c++)
2202
sfprintf(sfstderr, "[%d] %2d %s\n", c, state.view[c].pathlen, state.view[c].path);
2203
c = 1;
2204
}
2205
}
2206
else
2207
error(1, "%s: options are {blocked,buckets,hash,jobs,nametype,rules,stack,variables,view}", s);
2208
}
2209
else
2210
while (s)
2211
{
2212
if (r = getrule(s))
2213
{
2214
c = 1;
2215
dumprule(sfstderr, r);
2216
}
2217
if (v = getvar(s))
2218
{
2219
c = 1;
2220
sfprintf(sfstderr, "\n");
2221
dumpvar(sfstderr, v);
2222
if (r = staterule(VAR, NiL, s, 0))
2223
dumprule(sfstderr, r);
2224
}
2225
s = getarg(&rhs, NiL);
2226
}
2227
if (c)
2228
sfprintf(sfstderr, "\n");
2229
return;
2230
}
2231
2232
/*
2233
* construct the prerequsite list and attributes
2234
*/
2235
2236
x = 0;
2237
zero(clr);
2238
zero(set);
2239
set.op = op;
2240
if (!*rhs)
2241
set.op |= A_target;
2242
p = q = 0;
2243
while (s = getarg(&rhs, &set.op))
2244
{
2245
/*
2246
* <ATTRNAME><attribute> names (and sets) the attribute
2247
* <ATTRSET><attribute> sets the attribute
2248
* <ATTRCLEAR><attribute> clears the attribute
2249
*/
2250
2251
if (((c = *s) == ATTRSET || c == ATTRCLEAR) && *(s + 1))
2252
{
2253
*s = ATTRNAME;
2254
r = getrule(s);
2255
*s = c;
2256
if (!r)
2257
r = getrule(s + 1);
2258
if (!r || !(r->property & P_attribute))
2259
{
2260
if (r)
2261
{
2262
Flags_t m = 0;
2263
2264
/*
2265
* user controlled dynamic
2266
* staterule attributes
2267
*/
2268
2269
if (r == internal.entries)
2270
m = D_entries;
2271
else if (r == internal.member)
2272
m = D_member;
2273
else if (r == internal.regular)
2274
m = D_regular;
2275
else if (r == internal.scanned)
2276
m = D_scanned;
2277
if (m)
2278
{
2279
if (c == ATTRCLEAR)
2280
{
2281
set.op |= A_negate;
2282
att = &clr;
2283
}
2284
else
2285
att = &set;
2286
att->rule.dynamic |= m;
2287
continue;
2288
}
2289
}
2290
r = makerule(s);
2291
}
2292
}
2293
else
2294
r = makerule(s);
2295
if (r->property & P_attribute)
2296
{
2297
if (c == ATTRCLEAR)
2298
{
2299
set.op |= A_negate;
2300
att = &clr;
2301
}
2302
else
2303
att = &set;
2304
2305
/*
2306
* assertion attributes
2307
*/
2308
2309
if (r == internal.clear)
2310
att->op |= A_clear;
2311
else if (r == internal.copy)
2312
att->op |= A_copy;
2313
else if (r == internal.delete)
2314
att->op |= A_delete;
2315
else if (r == internal.insert)
2316
att->op |= A_insert;
2317
else if (r == internal.null)
2318
att->op |= A_null;
2319
else if (r == internal.special)
2320
att->op |= A_special;
2321
2322
/*
2323
* attributes not propagated by merge()
2324
*
2325
* NOTE: internal.make->make is cleared in immediate()
2326
*/
2327
2328
else if (r == internal.attribute)
2329
att->rule.property |= P_attribute;
2330
else if (r == internal.immediate)
2331
att->rule.property |= P_immediate;
2332
else if (r == internal.make)
2333
att->rule.property |= P_make;
2334
else if (r == internal.op)
2335
att->rule.property |= P_operator;
2336
else if (r == internal.readonly)
2337
att->rule.property |= P_readonly;
2338
else if (r == internal.scan)
2339
att->op |= A_scan;
2340
else if (r == internal.semaphore)
2341
{
2342
if (att->rule.semaphore < UCHAR_MAX)
2343
att->rule.semaphore++;
2344
else
2345
error(1, "%s: maximum semaphore count is %d", r->name, UCHAR_MAX - 1);
2346
}
2347
else if (r == internal.state)
2348
att->rule.property |= P_state;
2349
else if (r == internal.target)
2350
att->rule.property |= P_target;
2351
else if (r == internal.use)
2352
att->rule.property |= P_use;
2353
2354
/*
2355
* merge() handles the rest
2356
*/
2357
2358
else
2359
merge(r, &att->rule, MERGE_ATTR|MERGE_FORCE);
2360
}
2361
else
2362
{
2363
if ((set.op & (A_metarule|A_special)) == A_metarule || !*s)
2364
{
2365
if (!x)
2366
x = r;
2367
else if (!*s)
2368
error(1, "multiple prerequisite patterns in metarule assertion");
2369
else
2370
{
2371
while (c = *s++)
2372
{
2373
if (c == '%')
2374
sfputr(internal.tmp, "$(%)", -1);
2375
else
2376
sfputc(internal.tmp, c);
2377
}
2378
r = makerule(sfstruse(internal.tmp));
2379
}
2380
}
2381
else if (set.op & A_scope)
2382
{
2383
r->dynamic |= D_scope;
2384
set.rule.dynamic |= D_hasscope;
2385
if (state.user <= 1 && state.reading && state.makefile && (s = strchr(r->name, '=')) && *(s + 1) == '=')
2386
{
2387
*s = 0;
2388
if (nametype(r->name, NiL) & NAME_identifier)
2389
setvar(r->name, NiL, V_scan);
2390
*s = '=';
2391
}
2392
}
2393
if (!(set.rule.dynamic & D_dynamic) && !(r->dynamic & D_scope) && isdynamic(r->name))
2394
set.rule.dynamic |= D_dynamic;
2395
if (r->property & P_use)
2396
merge(r, &set.rule, MERGE_ATTR);
2397
if (!p)
2398
p = q = cons(r, NiL);
2399
else
2400
q = q->next = cons(r, NiL);
2401
if (!(r->dynamic & D_scope))
2402
set.op |= A_target;
2403
}
2404
}
2405
prereqs = p;
2406
if (*act || (set.op & (A_null|A_target)) || (set.rule.property & (P_make|P_local)) == (P_make|P_local))
2407
set.rule.property |= P_target;
2408
joint = (set.rule.property & P_joint) ? internal.joint : 0;
2409
jointproperty = 0;
2410
2411
/*
2412
* assert each target
2413
*/
2414
2415
name = getarg(&lhs, &set.op);
2416
while (name)
2417
{
2418
r = makerule(name);
2419
if (joint)
2420
{
2421
if (streq(r->name, "-"))
2422
{
2423
jointproperty |= P_dontcare;
2424
name = getarg(&lhs, &set.op);
2425
continue;
2426
}
2427
if (joint == internal.joint)
2428
{
2429
joint = catrule(internal.joint->name, ".", name, 1);
2430
joint->property |= P_joint|P_readonly|P_virtual;
2431
jointail = joint->prereqs = cons(r, NiL);
2432
}
2433
else
2434
jointail = jointail->next = cons(r, NiL);
2435
r->property |= jointproperty;
2436
}
2437
if ((set.op & (A_metarule|A_special)) == A_metarule)
2438
{
2439
Rule_t* in;
2440
Rule_t* out;
2441
2442
in = 0;
2443
if (*name == ATTRNAME)
2444
{
2445
for (s = name + 1; istype(*s, C_ID1|C_ID2); s++);
2446
if (*s == ATTRNAME && s > (name + 1) && (c = *++s))
2447
{
2448
*s = 0;
2449
in = getrule(name);
2450
*s = c;
2451
}
2452
}
2453
if (in)
2454
{
2455
/*
2456
* pattern association rule
2457
*/
2458
2459
if (*s != '%' || *(s + 1) != ATTRNAME || !(x = getrule(s + 1)) || !(x->property & P_attribute))
2460
x = makerule(s);
2461
addprereq(in, x, ((set.op & A_insert) || *(s + strlen(s) - 1) != '%') ? PREREQ_INSERT : PREREQ_APPEND);
2462
if (set.op & A_negate)
2463
{
2464
*name = ATTRCLEAR;
2465
merge(&clr.rule, makerule(name), MERGE_ATTR|MERGE_FORCE);
2466
*name = ATTRNAME;
2467
}
2468
name = getarg(&lhs, &set.op);
2469
}
2470
else
2471
{
2472
/*
2473
* metarule assertion
2474
*/
2475
2476
for (p = prereqs, prereqs = q = 0; p; q = p, p = p->next)
2477
{
2478
if (p->rule == x)
2479
{
2480
/*
2481
* rhs pattern
2482
*/
2483
2484
in = p->rule;
2485
if (q)
2486
q->next = p->next;
2487
}
2488
else if (!prereqs)
2489
prereqs = p;
2490
}
2491
c = ((set.op & A_clear) && !prereqs && !*act) ? PREREQ_DELETE : PREREQ_APPEND;
2492
out = *(r->name + 1) ? r : 0;
2493
2494
/*
2495
* update the metarule intermediate prerequisite graph
2496
*/
2497
2498
if (in)
2499
{
2500
r = metarule(in->name, r->name, 1);
2501
if (out)
2502
{
2503
metaclose(in, out, c);
2504
if (name = getarg(&lhs, &set.op))
2505
{
2506
addprereq(metainfo('S', in->name, out->name, 1), out, c);
2507
do
2508
{
2509
x = makerule(name);
2510
addprereq(metainfo('P', in->name, x->name, 1), out, c);
2511
addprereq(metainfo('S', in->name, out->name, 1), x, c);
2512
metaclose(in, x, c);
2513
} while (name = getarg(&lhs, &set.op));
2514
}
2515
}
2516
else
2517
addprereq(metainfo((set.rule.property & P_terminal) ? 'T' : 'N', NiL, NiL, 1), in, c);
2518
}
2519
else
2520
{
2521
if (out && c != PREREQ_DELETE)
2522
addprereq(internal.metarule, out, PREREQ_LENGTH);
2523
name = getarg(&lhs, &set.op);
2524
}
2525
}
2526
}
2527
else
2528
{
2529
name = getarg(&lhs, &set.op);
2530
if (!internal.main->prereqs && !state.global && !(set.rule.property & P_operator) && !(set.op & A_special) && !special(r) && !special(&set.rule))
2531
{
2532
internal.main->prereqs = cons(r, NiL);
2533
internal.main->dynamic &= ~D_compiled;
2534
}
2535
}
2536
if ((r->property & P_readonly) || (r->property & P_staterule) && !istype(*(r->name + 1), C_ID1))
2537
{
2538
if (r == internal.readonly)
2539
continue; /* drop this in 2000 */
2540
if (pp->fp != sfstdin)
2541
{
2542
error(2, "%s: %s atom cannot appear as target", r->name, (r->property & P_readonly) ? "readonly" : "staterule");
2543
continue;
2544
}
2545
else if (r->property & P_readonly)
2546
error(1, "%s: modifying readonly atom", r->name);
2547
}
2548
if (!((r->property|set.rule.property) & P_immediate) && (r->status == UPDATE || r->status == MAKING))
2549
{
2550
if (*act || (set.op & A_null))
2551
{
2552
error(2, "%s: cannot reset active target action", r->name);
2553
continue;
2554
}
2555
if (set.op & (A_clear|A_copy|A_delete|A_insert))
2556
{
2557
error(2, "%s: cannot reorder active target prerequisites", r->name);
2558
continue;
2559
}
2560
isactive = 1;
2561
}
2562
else
2563
isactive = 0;
2564
if (set.op & (A_clear|A_copy))
2565
{
2566
int dynamic;
2567
int property;
2568
2569
if (r->property & P_attribute)
2570
{
2571
error(2, "%s: atom cannot be cleared", r->name);
2572
continue;
2573
}
2574
dynamic = r->dynamic & (D_compiled);
2575
property = r->property & (P_state|P_staterule|P_statevar);
2576
if ((r->property & P_metarule) && (prereqs || *act || (set.op & A_null)))
2577
property |= r->property & (P_metarule|P_use);
2578
s = r->uname && !(r->property & P_state) ? r->uname : r->name;
2579
if (!(x = (r->property & P_state) ? rulestate(r, 0) : staterule(RULE, r, NiL, 0)) || r->prereqs != x->prereqs)
2580
freelist(r->prereqs);
2581
if (set.op & A_copy)
2582
{
2583
if (!prereqs || prereqs->next)
2584
{
2585
error(2, "%s: 1-1 copy only", r->name);
2586
continue;
2587
}
2588
x = prereqs->rule;
2589
*r = *x;
2590
r->name = s;
2591
r->uname = 0;
2592
r->prereqs = listcopy(x->prereqs);
2593
r->dynamic &= ~D_cached;
2594
r->dynamic |= dynamic;
2595
r->property |= property;
2596
continue;
2597
}
2598
zero(*r);
2599
r->name = s;
2600
r->dynamic = dynamic;
2601
r->property = property;
2602
if (r->property & P_state)
2603
state.savestate = 1;
2604
}
2605
if (set.op & A_delete)
2606
{
2607
for (p = prereqs; p; p = p->next)
2608
addprereq(r, p->rule, PREREQ_DELETE);
2609
negate(&set.rule, r);
2610
r->dynamic &= ~D_cached;
2611
continue;
2612
}
2613
if (set.op & A_null)
2614
r->action = null;
2615
if (prereqs)
2616
{
2617
p = name ? listcopy(prereqs) : prereqs;
2618
if ((set.op & A_insert) && (r->property & (P_joint|P_target)) == (P_joint|P_target))
2619
r->prereqs->next = append(p, r->prereqs->next);
2620
else
2621
{
2622
if (isactive && (set.rule.dynamic & D_dynamic))
2623
{
2624
r->dynamic |= D_dynamic;
2625
q = r->prereqs;
2626
r->prereqs = p;
2627
dynamic(r);
2628
p = r->prereqs;
2629
r->prereqs = q;
2630
}
2631
r->prereqs = (set.op & A_insert) ? append(p, r->prereqs) : append(r->prereqs, p);
2632
}
2633
remdup(r->prereqs);
2634
if (r->property & P_state)
2635
state.savestate = 1;
2636
}
2637
2638
/*
2639
* check action
2640
*/
2641
2642
if (*act)
2643
{
2644
if (!(s = r->action) || !streq(act, s))
2645
r->action = strdup(act); /* XXX: possible leak */
2646
if (s && r->action != s && !state.user && !(set.rule.property & P_operator) && !(set.op & A_special) && !special(r) && !special(&set.rule))
2647
error(1, "multiple actions for %s", r->name);
2648
}
2649
2650
/*
2651
* assign attributes
2652
*/
2653
2654
merge(&set.rule, r, MERGE_ATTR|MERGE_FORCE);
2655
if (set.op & A_negate)
2656
negate(&clr.rule, r);
2657
2658
/*
2659
* attributes not handled by merge()
2660
*/
2661
2662
if (!isactive && ((set.rule.dynamic & D_dynamic) || isdynamic(r->name)))
2663
r->dynamic |= D_dynamic;
2664
if (((set.rule.property|clr.rule.property) & P_functional) && !(r->property & P_state) && ((v = getvar(r->name)) || (v = setvar(r->name, null, 0))))
2665
{
2666
if (set.rule.property & P_functional)
2667
v->property |= V_functional;
2668
else
2669
v->property &= ~V_functional;
2670
}
2671
if (set.rule.property & P_immediate)
2672
r->property |= (P_ignore|P_immediate);
2673
if (set.rule.property & P_operator)
2674
{
2675
s = r->name;
2676
if (*s == ':' && istype(*++s, C_ID1))
2677
while (istype(*++s, C_ID2));
2678
if (*s == ':' && !*++s)
2679
r->property |= P_operator;
2680
else
2681
error(2, "%s: invalid operator name", r->name);
2682
}
2683
if (set.rule.property & P_readonly)
2684
r->property |= P_readonly;
2685
if (set.rule.semaphore)
2686
r->semaphore = set.rule.semaphore + 1;
2687
if ((set.rule.property & P_target) && !((clr.rule.property | r->property) & P_target))
2688
{
2689
r->property |= P_target;
2690
if (state.targetcontext && (s = strrchr(r->name, '/')))
2691
makerule(s + 1)->dynamic |= D_context;
2692
}
2693
if ((set.rule.property & P_use) && (!(r->property & P_attribute) || !r->attribute))
2694
r->property |= P_use;
2695
2696
/*
2697
* user controlled dynamic staterule attributes
2698
*/
2699
2700
if ((set.rule.dynamic | clr.rule.dynamic) & ~D_dynamic)
2701
{
2702
r->dynamic |= (set.rule.dynamic & ~D_dynamic);
2703
r->dynamic &= ~(clr.rule.dynamic & ~D_dynamic);
2704
if (x = staterule(RULE, r, NiL, 0))
2705
{
2706
x->dynamic |= (set.rule.dynamic & ~D_dynamic);
2707
x->dynamic &= ~(clr.rule.dynamic & ~D_dynamic);
2708
if (clr.rule.dynamic & D_scanned)
2709
x->property |= P_force;
2710
}
2711
if (x = staterule(PREREQS, r, NiL, 0))
2712
{
2713
x->dynamic |= (set.rule.dynamic & ~D_dynamic);
2714
x->dynamic &= ~(clr.rule.dynamic & ~D_dynamic);
2715
if (clr.rule.dynamic & D_scanned)
2716
x->property |= P_force;
2717
}
2718
}
2719
2720
/*
2721
* these are done after attributes have been assigned
2722
*/
2723
2724
if ((set.rule.property & P_attribute) && !(r->property & P_attribute))
2725
{
2726
r->property |= P_attribute;
2727
if (!(r->property & P_use))
2728
{
2729
if (internal.attribute->attribute << 1)
2730
{
2731
r->dynamic |= D_index;
2732
r->attribute = internal.attribute->attribute;
2733
internal.attribute->attribute <<= 1;
2734
addprereq(internal.attribute, r, PREREQ_APPEND);
2735
}
2736
else
2737
error(1, "%s: too many named attributes", r->name);
2738
}
2739
}
2740
if (joint)
2741
r->prereqs = cons(joint, r->prereqs);
2742
if ((set.op & A_scan) && !r->scan)
2743
{
2744
if (internal.scan->scan == SCAN_MAX)
2745
error(1, "%s: too many scan strategies", r->name);
2746
else
2747
{
2748
r->dynamic |= D_index;
2749
r->property |= P_attribute;
2750
r->scan = internal.scan->scan++;
2751
addprereq(internal.scan, r, PREREQ_APPEND);
2752
}
2753
}
2754
if (!state.init && !state.readonly && (!state.op && state.reading || !(r->property & P_immediate)))
2755
r->dynamic &= ~D_compiled;
2756
r->dynamic &= ~D_cached;
2757
2758
/*
2759
* do immediate actions right away
2760
*/
2761
2762
if (r->property & P_immediate)
2763
immediate(r);
2764
}
2765
}
2766
2767
/*
2768
* parse an assignment statement
2769
*/
2770
2771
static void
2772
assignment(char* lhs, int op, char* rhs)
2773
{
2774
register Rule_t* r;
2775
register char* s;
2776
register int n;
2777
Var_t* v;
2778
2779
if (internal.assign_p->prereqs && (r = associate(internal.assign_p, NiL, lhs, NiL)) && r->prereqs && (r = r->prereqs->rule) && (r->property & P_operator) && !r->uname)
2780
{
2781
s = r->uname = r->name;
2782
r->name = (op & OP_APPEND) ? "+=" : (op & OP_AUXILIARY) ? "&=" : (op & OP_STATE) ? "==" : "=";
2783
apply(r, lhs, rhs, NiL, CO_ALWAYS|CO_LOCAL|CO_URGENT);
2784
r->name = s;
2785
r->uname = 0;
2786
return;
2787
}
2788
debug((-6, "assignment: lhs=`%s' %s%srhs=`%-.1024s'", lhs, (op & OP_APPEND) ? "[append] " : null, (op & OP_STATE) ? "[state] " : null, rhs));
2789
if (!(s = getarg(&lhs, NiL)))
2790
error(1, "variable name missing in assignment");
2791
else
2792
{
2793
if (getarg(&lhs, NiL))
2794
error(1, "only one variable per assignment");
2795
n = 0;
2796
if (op & OP_APPEND)
2797
n |= V_append;
2798
if (op & OP_AUXILIARY)
2799
n |= V_auxiliary;
2800
if (op & OP_STATE)
2801
n |= V_scan;
2802
if (pp->scoped)
2803
{
2804
declare(s, NiL, n|V_scope);
2805
v = setvar(s, rhs, n);
2806
if (state.localview && (!(r = staterule(VAR, NiL, s, 0)) || !(r->property & P_parameter)))
2807
{
2808
Sfio_t* tmp;
2809
2810
tmp = sfstropen();
2811
expand(tmp, rhs);
2812
localvar(NiL, v, sfstruse(tmp), V_local_D);
2813
sfstrclose(tmp);
2814
}
2815
}
2816
else
2817
setvar(s, rhs, n);
2818
}
2819
}
2820
2821
/*
2822
* invoke or verify rules s
2823
*/
2824
2825
void
2826
rules(char* s)
2827
{
2828
register char* t;
2829
register char* e;
2830
2831
if (e = strchr(s, '\n'))
2832
*e = 0;
2833
sfputr(internal.tmp, s, 0);
2834
if (e)
2835
*e = '\n';
2836
s = sfstruse(internal.tmp);
2837
if (!(t = getarg(&s, NiL)))
2838
t = null;
2839
if (state.rules)
2840
{
2841
edit(internal.nam, t, DELETE, KEEP, DELETE);
2842
edit(internal.wrk, state.rules, DELETE, KEEP, DELETE);
2843
if (strcmp(sfstruse(internal.nam), sfstruse(internal.wrk)))
2844
error(3, "%s: incompatible with current base rules %s", t, state.rules);
2845
}
2846
else if (t == null)
2847
state.rules = null;
2848
else
2849
state.rules = makerule(t)->name;
2850
if (t != null && (t = getarg(&s, NiL)))
2851
error(3, "%s: invalid base rule argument", t);
2852
state.explicitrules = 1;
2853
}
2854
2855
/*
2856
* external PUSHLOCAL()
2857
*/
2858
2859
void*
2860
pushlocal(void)
2861
{
2862
register Local_t* p;
2863
2864
PUSHLOCAL(p);
2865
return (void*)pp->local;
2866
}
2867
2868
/*
2869
* external POPLOCAL()
2870
* pos is return value of previous pushlocal()
2871
*/
2872
2873
void
2874
poplocal(void* pos)
2875
{
2876
register Local_t* p;
2877
register Local_t* t;
2878
2879
p = (Local_t*)pos;
2880
while (pp->local != p)
2881
{
2882
pp->local->bucket->value = (char*)pp->local->oldv;
2883
t = pp->local;
2884
pp->local = pp->local->next;
2885
freelocal(t);
2886
}
2887
POPLOCAL(p);
2888
}
2889
2890
static long makeexpr(const char*, char**, void*);
2891
2892
/*
2893
* <var>
2894
* <var> = <expression>
2895
* [ <var> = ] <quote> ... <quote>
2896
*/
2897
2898
static char*
2899
nextarg(char* s, char** p, char** end, long* val)
2900
{
2901
register char* arg;
2902
register int c;
2903
char* var;
2904
char* varend;
2905
char buf[10];
2906
long n;
2907
2908
if ((c = *s) && c != MARK_QUOTE && c != '"')
2909
{
2910
if (!istype(*s, C_VARIABLE1))
2911
error(3, "argument expected in expression [%s]", s);
2912
for (var = s++; istype(*s, C_VARIABLE2); s++);
2913
varend = s;
2914
while (isspace(*s))
2915
s++;
2916
if (*s != '=' || *(s + 1) == '=')
2917
{
2918
c = *varend;
2919
*varend = 0;
2920
arg = getval(var, VAL_PRIMARY|VAL_AUXILIARY);
2921
*varend = c;
2922
*p = s;
2923
2924
/*
2925
* determine if in string or numeric context
2926
*/
2927
2928
if ((*s == '!' || *s == '=') && *(s + 1) == '=')
2929
{
2930
s++;
2931
while (isspace(*++s));
2932
if (*s == MARK_QUOTE)
2933
{
2934
*end = s;
2935
return arg;
2936
}
2937
}
2938
if (!*arg)
2939
*val = 0;
2940
else
2941
{
2942
*val = strtol(arg, &s, 0);
2943
if (*s)
2944
*val = 1;
2945
}
2946
return 0;
2947
}
2948
while (isspace(*++s));
2949
}
2950
else
2951
var = 0;
2952
if ((c = *s) == MARK_QUOTE)
2953
{
2954
for (arg = ++s; *s && *s != c; s++);
2955
*end = s;
2956
if (*s)
2957
while (isspace(*++s));
2958
}
2959
else if (c == '"')
2960
{
2961
for (arg = ++s; *s && *s != c; s++)
2962
if (*s == '\\' && *(s + 1))
2963
s++;
2964
*end = s;
2965
if (*s)
2966
while (isspace(*++s));
2967
}
2968
else if (var)
2969
{
2970
sfsprintf(arg = buf, sizeof(buf), "%ld", *val = strexpr(s, &s, makeexpr, NiL));
2971
end = 0;
2972
}
2973
else
2974
error(3, "string argument expected in expression");
2975
if (var)
2976
{
2977
c = *varend;
2978
*varend = 0;
2979
if (end)
2980
{
2981
n = **end;
2982
**end = 0;
2983
2984
/*
2985
* XXX: this handles the symptom but not the bug
2986
*/
2987
2988
if (*arg == '"' && !*(arg + 1))
2989
arg++;
2990
}
2991
debug((-6, "assignment: lhs=`%s' rhs=`%s'", var, arg));
2992
setvar(var, arg, 0);
2993
*varend = c;
2994
if (end)
2995
**end = n;
2996
}
2997
*p = s;
2998
return end ? arg : 0;
2999
}
3000
3001
/*
3002
* supplementary make expression evaluator for strexpr()
3003
*
3004
* "..." == "..." strmatch()
3005
* "..." != "..." strmatch()
3006
* "..." < "..." strcoll()
3007
* "..." <= "..." strcoll()
3008
* "..." > "..." strcoll()
3009
* "..." >= "..." strcoll()
3010
* <var> "<value>"
3011
* <var> = "..." "..."
3012
* ( <var> = "..." ) "..."
3013
* <var> = <expression> <expression> ? "1" : ""
3014
*
3015
* NOTE: '"' translated to MARK_QUOTE by expr()
3016
*/
3017
3018
static long
3019
makeexpr(const char* cs, char** p, void* handle)
3020
{
3021
char* s = (char*)cs;
3022
int c;
3023
int q;
3024
int c1;
3025
int c2;
3026
int m1;
3027
int m2;
3028
char* paren;
3029
char* s1;
3030
char* s2;
3031
char* e1;
3032
char* e2;
3033
long n;
3034
3035
NoP(handle);
3036
if (!s)
3037
error(3, "%s in expression", *p);
3038
else if (!(s1 = nextarg(s, &s, &e1, &n)))
3039
/* n == expression value */;
3040
else
3041
{
3042
if ((c = *s) == ')')
3043
{
3044
paren = s;
3045
e2 = s;
3046
while (isspace(*++s));
3047
}
3048
else
3049
paren = 0;
3050
if (!(c = *s) || c != '<' && c != '>' && (*(s + 1) != '=' || c != '!' && c != '='))
3051
{
3052
n = e1 > s1;
3053
if (paren)
3054
s = paren;
3055
}
3056
else
3057
{
3058
q = *++s != '=';
3059
while (isspace(*++s));
3060
if (!(s2 = nextarg(s, &s, &e2, &n)))
3061
n = 0;
3062
else
3063
{
3064
c1 = *e1;
3065
*e1 = 0;
3066
c2 = *e2;
3067
*e2 = 0;
3068
if (state.context)
3069
{
3070
if (*s1 == MARK_CONTEXT && *(e1 - 1) == MARK_CONTEXT)
3071
{
3072
*(e1 - 1) = 0;
3073
m1 = 1;
3074
}
3075
else
3076
m1 = 0;
3077
if (*s2 == MARK_CONTEXT && *(e2 - 1) == MARK_CONTEXT)
3078
{
3079
*(e2 - 1) = 0;
3080
m2 = 1;
3081
}
3082
else
3083
m2 = 0;
3084
}
3085
switch (c)
3086
{
3087
case '>':
3088
n = strcoll(s1, s2) >= q;
3089
break;
3090
case '<':
3091
n = strcoll(s2, s1) >= q;
3092
break;
3093
case '!':
3094
n = !strmatch(s1, s2);
3095
break;
3096
default:
3097
n = strmatch(s1, s2);
3098
break;
3099
}
3100
if (state.context)
3101
{
3102
if (m1)
3103
*(e1 - 1) = MARK_CONTEXT;
3104
if (m2)
3105
*(e2 - 1) = MARK_CONTEXT;
3106
}
3107
*e1 = c1;
3108
*e2 = c2;
3109
}
3110
}
3111
if (paren)
3112
{
3113
if (!*s)
3114
s--;
3115
*s = ')';
3116
}
3117
}
3118
*p = s;
3119
return n;
3120
}
3121
3122
/*
3123
* expression evaluation on s using temporary string xp
3124
* '"' temporarily converted to MARK_QUOTE
3125
* s is first expanded
3126
*/
3127
3128
long
3129
expr(Sfio_t* xp, register char* s)
3130
{
3131
register char* t;
3132
register int p;
3133
register char** v;
3134
int c;
3135
long top;
3136
char* restore[PARSEDEPTH];
3137
3138
v = restore;
3139
t = s;
3140
p = 0;
3141
for (;;)
3142
switch (*t++)
3143
{
3144
case '(':
3145
if (p)
3146
p++;
3147
break;
3148
case ')':
3149
if (p)
3150
p--;
3151
break;
3152
case '"':
3153
if (p <= 1)
3154
{
3155
p = !p;
3156
if (v < &restore[elementsof(restore)])
3157
*(*v++ = t - 1) = MARK_QUOTE;
3158
}
3159
break;
3160
case '\\':
3161
if (*t++)
3162
break;
3163
/*FALLTHROUGH*/
3164
case 0:
3165
case '\n':
3166
c = *--t;
3167
*t = 0;
3168
top = sfstrtell(xp);
3169
expand(xp, s);
3170
sfputc(xp, 0);
3171
while (v > restore)
3172
**--v = '"';
3173
*t = c;
3174
return strexpr(sfstrseek(xp, top, SEEK_SET), NiL, makeexpr, NiL);
3175
}
3176
}
3177
3178
/*
3179
* error exit during interpreter()
3180
*/
3181
3182
static void
3183
exit_interpreter(int code)
3184
{
3185
NoP(code);
3186
sfsync(sfstdout);
3187
sfsync(sfstderr);
3188
longjmp(state.resume.label, 1);
3189
finish(code);
3190
}
3191
3192
/*
3193
* interactive query loop
3194
*/
3195
3196
void
3197
interpreter(char* msg)
3198
{
3199
int level;
3200
void (*errexit)(int);
3201
Frame_t frame;
3202
Label_t resume;
3203
3204
if (msg)
3205
error(0, "\n%s\n", msg);
3206
level = pp - &parsestack[0];
3207
errexit = error_info.exit;
3208
error_info.exit = exit_interpreter;
3209
zero(frame);
3210
frame.target = internal.query;
3211
frame.parent = state.frame;
3212
frame.previous = frame.target->active;
3213
state.frame = frame.target->active = &frame;
3214
state.keepgoing |= 2;
3215
resume = state.resume;
3216
if (setjmp(state.resume.label))
3217
{
3218
unparse(level);
3219
state.hold = 0;
3220
state.frame = frame.target->active = &frame;
3221
sfclrlock(sfstdin);
3222
}
3223
else
3224
state.interpreter++;
3225
parse(sfstdin, NiL, "query", NiL);
3226
state.interpreter--;
3227
state.resume = resume;
3228
state.keepgoing &= 1;
3229
frame.target->active = frame.previous;
3230
state.frame = frame.parent;
3231
sfclrlock(sfstdin);
3232
error_info.exit = errexit;
3233
if (msg)
3234
error(0, "\n");
3235
}
3236
3237
/*
3238
* read and parse file fp or line buffer bp
3239
* non-zero returned if target to be updated
3240
*/
3241
3242
int
3243
parse(Sfio_t* fp, char* bp, char* name, Sfio_t* scoped)
3244
{
3245
register int op;
3246
register Local_t* lcl;
3247
char* lhs;
3248
char* rhs;
3249
char* act;
3250
char* alt;
3251
Rule_t* opr;
3252
Local_t* olcl;
3253
Sfio_t* buf;
3254
Sfio_t* tmp;
3255
3256
if (pp->newline)
3257
*pp->bp = '\n';
3258
else if (!pp->fp && pp->bp && !*pp->bp)
3259
{
3260
error(1, "parse: early pop");
3261
return 0;
3262
}
3263
PUSHLOCAL(lcl);
3264
if (++pp >= &parsestack[elementsof(parsestack)])
3265
error(3, "input nesting too deep");
3266
if ((pp->block = (pp - 1)->cp + 1) >= &constack[elementsof(constack)])
3267
error(3, "control block nesting too deep");
3268
#if DEBUG
3269
message((fp ? -2 : -7, "reading %s", name));
3270
#else
3271
if (fp)
3272
message((-2, "reading %s", name));
3273
#endif
3274
3275
/*
3276
* push the parse stack
3277
*/
3278
3279
if (pp->fp = fp)
3280
{
3281
pp->ip = sfstropen();
3282
pp->prompt = fp == sfstdin && isatty(sffileno(fp)) && isatty(sffileno(sfstderr));
3283
if (fp == sfstdin)
3284
sfdcslow(fp);
3285
}
3286
else
3287
{
3288
pp->bp = bp;
3289
pp->prompt = 0;
3290
}
3291
pp->name = error_info.file = name;
3292
pp->line = error_info.line;
3293
error_info.line = 0;
3294
pp->argc = 0;
3295
pp->stashget = 0;
3296
pp->stashput = 0;
3297
pp->pushback = 0;
3298
pp->eval = 0;
3299
pp->indent = 0;
3300
pp->newline = 0;
3301
pp->splice = 0;
3302
pp->status = UPDATE;
3303
pp->cp = pp->block;
3304
pp->cp->flags = 0;
3305
if (pp->scoped = scoped)
3306
pp->local = (pp - 1)->local;
3307
3308
/*
3309
* statement parse loop
3310
*/
3311
3312
buf = sfstropen();
3313
for (;;)
3314
{
3315
op = statement(buf, &lhs, &opr, &rhs, &act);
3316
if (trap() && !op)
3317
continue;
3318
if (!op)
3319
break;
3320
switch (op & OP_STATEMENT)
3321
{
3322
3323
case OP_ASSERT:
3324
assertion(lhs, opr, rhs, act, 0);
3325
break;
3326
3327
case OP_ASSIGN:
3328
assignment(lhs, op, rhs);
3329
break;
3330
3331
case OP_EMPTY:
3332
if (*lhs || *act)
3333
{
3334
tmp = sfstropen();
3335
if (*lhs)
3336
{
3337
expand(tmp, lhs);
3338
rhs = lhs = sfstruse(tmp);
3339
sfputc(internal.nam, '.');
3340
while ((op = *rhs++) && !isspace(op))
3341
sfputc(internal.nam, islower(op) ? toupper(op) : isupper(op) ? tolower(op) : op);
3342
rhs--;
3343
alt = sfstruse(internal.nam);
3344
}
3345
else
3346
{
3347
sfputr(tmp, internal.always->name, -1);
3348
rhs = lhs = alt = sfstruse(tmp);
3349
}
3350
if (!(opr = getrule(alt)) || !(opr->property & (P_attribute|P_functional|P_immediate)))
3351
{
3352
if (pp->fp == sfstdin)
3353
{
3354
if ((op = *++alt) == 'P' && (!*(alt + 1) || !strcmp(alt, "PRINT")))
3355
{
3356
while (isspace(*rhs))
3357
rhs++;
3358
sfputr(sfstdout, rhs, '\n');
3359
sfstrclose(tmp);
3360
break;
3361
}
3362
if (op == 'Q' && (!*(alt + 1) || !strcmp(alt, "QUIT")))
3363
{
3364
if (*rhs)
3365
finish(strtol(rhs, NiL, 0));
3366
sfstrclose(tmp);
3367
goto quit;
3368
}
3369
}
3370
else if (!*act)
3371
error(3, "no operator on line");
3372
if (*act)
3373
{
3374
if (*rhs)
3375
{
3376
*rhs++ = 0;
3377
while (isspace(*rhs))
3378
rhs++;
3379
}
3380
opr = 0;
3381
}
3382
else
3383
{
3384
opr = internal.query;
3385
rhs = lhs;
3386
}
3387
}
3388
if (opr)
3389
{
3390
if (opr->property & P_functional)
3391
{
3392
while (isspace(*rhs))
3393
rhs++;
3394
maketop(opr, 0, rhs);
3395
sfstrclose(tmp);
3396
break;
3397
}
3398
sfputr(internal.nam, opr->name, -1);
3399
alt = sfstruse(internal.nam);
3400
if (opr->property & P_immediate)
3401
lhs = alt;
3402
else
3403
{
3404
lhs = rhs;
3405
rhs = alt;
3406
}
3407
}
3408
assertion(lhs, NiL, rhs, act, A_special);
3409
sfstrclose(tmp);
3410
}
3411
break;
3412
3413
#if DEBUG
3414
default:
3415
error(PANIC, "invalid statement type %d", op);
3416
#endif
3417
}
3418
}
3419
quit:
3420
sfstrclose(buf);
3421
3422
/*
3423
* pop the parse stack
3424
*/
3425
3426
if (pp->cp > pp->block)
3427
error(3, "missing %d closing end statement%s", pp->cp - pp->block, pp->cp - pp->block == 1 ? null : "s");
3428
if (pp->fp)
3429
sfstrclose(pp->ip);
3430
else if (pp->newline)
3431
*pp->bp = '\n';
3432
if (scoped)
3433
{
3434
(pp - 1)->local = pp->local;
3435
pp->local = 0;
3436
}
3437
else if (lcl = pp->local)
3438
{
3439
pp->local = 0;
3440
while (lcl)
3441
{
3442
lcl->bucket->value = (char*)lcl->oldv;
3443
olcl = lcl;
3444
lcl = lcl->next;
3445
freelocal(olcl);
3446
}
3447
}
3448
error_info.line = pp->line;
3449
pp--;
3450
if (pp->newline)
3451
*pp->bp = 0;
3452
POPLOCAL(lcl);
3453
error_info.file = pp->name;
3454
#if DEBUG
3455
message((fp ? -2 : -7, "popping %s", name));
3456
#else
3457
if (fp)
3458
message((-2, "popping %s", name));
3459
#endif
3460
return (pp + 1)->status;
3461
}
3462
3463
char*
3464
parsefile(void)
3465
{
3466
register Parseinfo_t* pi;
3467
3468
if (state.loading)
3469
return state.loading;
3470
for (pi = pp; pi >= &parsestack[0]; pi--)
3471
if (pi->fp)
3472
return pi->name;
3473
return error_info.file;
3474
}
3475
3476