#
source:
trunk/third/tcsh/sh.parse.c
@
12039

Revision 12039, 13.8 KB checked in by danw, 26 years ago (diff) |
---|

Line | |
---|---|

1 | /* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/sh.parse.c,v 1.1.1.2 1998-10-03 21:10:05 danw Exp $ */ |

2 | /* |

3 | * sh.parse.c: Interpret a list of tokens |

4 | */ |

5 | /*- |

6 | * Copyright (c) 1980, 1991 The Regents of the University of California. |

7 | * All rights reserved. |

8 | * |

9 | * Redistribution and use in source and binary forms, with or without |

10 | * modification, are permitted provided that the following conditions |

11 | * are met: |

12 | * 1. Redistributions of source code must retain the above copyright |

13 | * notice, this list of conditions and the following disclaimer. |

14 | * 2. Redistributions in binary form must reproduce the above copyright |

15 | * notice, this list of conditions and the following disclaimer in the |

16 | * documentation and/or other materials provided with the distribution. |

17 | * 3. All advertising materials mentioning features or use of this software |

18 | * must display the following acknowledgement: |

19 | * This product includes software developed by the University of |

20 | * California, Berkeley and its contributors. |

21 | * 4. Neither the name of the University nor the names of its contributors |

22 | * may be used to endorse or promote products derived from this software |

23 | * without specific prior written permission. |

24 | * |

25 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |

26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |

27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |

28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |

29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |

30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |

31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |

32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |

33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |

34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |

35 | * SUCH DAMAGE. |

36 | */ |

37 | #include "sh.h" |

38 | |

39 | RCSID("$Id: sh.parse.c,v 1.1.1.2 1998-10-03 21:10:05 danw Exp $") |

40 | |

41 | /* |

42 | * C shell |

43 | */ |

44 | static void asyntax __P((struct wordent *, struct wordent *)); |

45 | static void asyn0 __P((struct wordent *, struct wordent *)); |

46 | static void asyn3 __P((struct wordent *, struct wordent *)); |

47 | static struct wordent *freenod __P((struct wordent *, struct wordent *)); |

48 | static struct command *syn0 __P((struct wordent *, struct wordent *, int)); |

49 | static struct command *syn1 __P((struct wordent *, struct wordent *, int)); |

50 | static struct command *syn1a __P((struct wordent *, struct wordent *, int)); |

51 | static struct command *syn1b __P((struct wordent *, struct wordent *, int)); |

52 | static struct command *syn2 __P((struct wordent *, struct wordent *, int)); |

53 | static struct command *syn3 __P((struct wordent *, struct wordent *, int)); |

54 | |

55 | #define ALEFT 51 /* max of 50 alias expansions */ |

56 | #define HLEFT 11 /* max of 10 history expansions */ |

57 | /* |

58 | * Perform aliasing on the word list lexp |

59 | * Do a (very rudimentary) parse to separate into commands. |

60 | * If word 0 of a command has an alias, do it. |

61 | * Repeat a maximum of 50 times. |

62 | */ |

63 | static int aleft; |

64 | extern int hleft; |

65 | void |

66 | alias(lexp) |

67 | register struct wordent *lexp; |

68 | { |

69 | jmp_buf_t osetexit; |

70 | |

71 | aleft = ALEFT; |

72 | hleft = HLEFT; |

73 | getexit(osetexit); |

74 | (void) setexit(); |

75 | if (haderr) { |

76 | resexit(osetexit); |

77 | reset(); |

78 | } |

79 | if (--aleft == 0) |

80 | stderror(ERR_ALIASLOOP); |

81 | asyntax(lexp->next, lexp); |

82 | resexit(osetexit); |

83 | } |

84 | |

85 | static void |

86 | asyntax(p1, p2) |

87 | register struct wordent *p1, *p2; |

88 | { |

89 | while (p1 != p2) |

90 | if (any(";&\n", p1->word[0])) |

91 | p1 = p1->next; |

92 | else { |

93 | asyn0(p1, p2); |

94 | return; |

95 | } |

96 | } |

97 | |

98 | static void |

99 | asyn0(p1, p2) |

100 | struct wordent *p1; |

101 | register struct wordent *p2; |

102 | { |

103 | register struct wordent *p; |

104 | register int l = 0; |

105 | |

106 | for (p = p1; p != p2; p = p->next) |

107 | switch (p->word[0]) { |

108 | |

109 | case '(': |

110 | l++; |

111 | continue; |

112 | |

113 | case ')': |

114 | l--; |

115 | if (l < 0) |

116 | stderror(ERR_TOOMANYRP); |

117 | continue; |

118 | |

119 | case '>': |

120 | if (p->next != p2 && eq(p->next->word, STRand)) |

121 | p = p->next; |

122 | continue; |

123 | |

124 | case '&': |

125 | case '|': |

126 | case ';': |

127 | case '\n': |

128 | if (l != 0) |

129 | continue; |

130 | asyn3(p1, p); |

131 | asyntax(p->next, p2); |

132 | return; |

133 | |

134 | default: |

135 | break; |

136 | } |

137 | if (l == 0) |

138 | asyn3(p1, p2); |

139 | } |

140 | |

141 | static void |

142 | asyn3(p1, p2) |

143 | struct wordent *p1; |

144 | register struct wordent *p2; |

145 | { |

146 | register struct varent *ap; |

147 | struct wordent alout; |

148 | register bool redid; |

149 | |

150 | if (p1 == p2) |

151 | return; |

152 | if (p1->word[0] == '(') { |

153 | for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev) |

154 | if (p2 == p1) |

155 | return; |

156 | if (p2 == p1->next) |

157 | return; |

158 | asyn0(p1->next, p2); |

159 | return; |

160 | } |

161 | ap = adrof1(p1->word, &aliases); |

162 | if (ap == 0) |

163 | return; |

164 | alhistp = p1->prev; |

165 | alhistt = p2; |

166 | alvec = ap->vec; |

167 | redid = lex(&alout); |

168 | alhistp = alhistt = 0; |

169 | alvec = 0; |

170 | if (seterr) { |

171 | freelex(&alout); |

172 | stderror(ERR_OLD); |

173 | } |

174 | if (p1->word[0] && eq(p1->word, alout.next->word)) { |

175 | Char *cp = alout.next->word; |

176 | |

177 | alout.next->word = Strspl(STRQNULL, cp); |

178 | xfree((ptr_t) cp); |

179 | } |

180 | p1 = freenod(p1, redid ? p2 : p1->next); |

181 | if (alout.next != &alout) { |

182 | p1->next->prev = alout.prev->prev; |

183 | alout.prev->prev->next = p1->next; |

184 | alout.next->prev = p1; |

185 | p1->next = alout.next; |

186 | xfree((ptr_t) alout.prev->word); |

187 | xfree((ptr_t) (alout.prev)); |

188 | } |

189 | reset(); /* throw! */ |

190 | } |

191 | |

192 | static struct wordent * |

193 | freenod(p1, p2) |

194 | register struct wordent *p1, *p2; |

195 | { |

196 | register struct wordent *retp = p1->prev; |

197 | |

198 | while (p1 != p2) { |

199 | xfree((ptr_t) p1->word); |

200 | p1 = p1->next; |

201 | xfree((ptr_t) (p1->prev)); |

202 | } |

203 | retp->next = p2; |

204 | p2->prev = retp; |

205 | return (retp); |

206 | } |

207 | |

208 | #define P_HERE 1 |

209 | #define P_IN 2 |

210 | #define P_OUT 4 |

211 | #define P_DIAG 8 |

212 | |

213 | /* |

214 | * syntax |

215 | * empty |

216 | * syn0 |

217 | */ |

218 | struct command * |

219 | syntax(p1, p2, flags) |

220 | register struct wordent *p1, *p2; |

221 | int flags; |

222 | { |

223 | |

224 | while (p1 != p2) |

225 | if (any(";&\n", p1->word[0])) |

226 | p1 = p1->next; |

227 | else |

228 | return (syn0(p1, p2, flags)); |

229 | return (0); |

230 | } |

231 | |

232 | /* |

233 | * syn0 |

234 | * syn1 |

235 | * syn1 & syntax |

236 | */ |

237 | static struct command * |

238 | syn0(p1, p2, flags) |

239 | struct wordent *p1, *p2; |

240 | int flags; |

241 | { |

242 | register struct wordent *p; |

243 | register struct command *t, *t1; |

244 | int l; |

245 | |

246 | l = 0; |

247 | for (p = p1; p != p2; p = p->next) |

248 | switch (p->word[0]) { |

249 | |

250 | case '(': |

251 | l++; |

252 | continue; |

253 | |

254 | case ')': |

255 | l--; |

256 | if (l < 0) |

257 | seterror(ERR_TOOMANYRP); |

258 | continue; |

259 | |

260 | case '|': |

261 | if (p->word[1] == '|') |

262 | continue; |

263 | /*FALLTHROUGH*/ |

264 | |

265 | case '>': |

266 | if (p->next != p2 && eq(p->next->word, STRand)) |

267 | p = p->next; |

268 | continue; |

269 | |

270 | case '&': |

271 | if (l != 0) |

272 | break; |

273 | if (p->word[1] == '&') |

274 | continue; |

275 | t1 = syn1(p1, p, flags); |

276 | if (t1->t_dtyp == NODE_LIST || |

277 | t1->t_dtyp == NODE_AND || |

278 | t1->t_dtyp == NODE_OR) { |

279 | t = (struct command *) xcalloc(1, sizeof(*t)); |

280 | t->t_dtyp = NODE_PAREN; |

281 | t->t_dflg = F_AMPERSAND | F_NOINTERRUPT; |

282 | t->t_dspr = t1; |

283 | t1 = t; |

284 | } |

285 | else |

286 | t1->t_dflg |= F_AMPERSAND | F_NOINTERRUPT; |

287 | t = (struct command *) xcalloc(1, sizeof(*t)); |

288 | t->t_dtyp = NODE_LIST; |

289 | t->t_dflg = 0; |

290 | t->t_dcar = t1; |

291 | t->t_dcdr = syntax(p, p2, flags); |

292 | return (t); |

293 | default: |

294 | break; |

295 | } |

296 | if (l == 0) |

297 | return (syn1(p1, p2, flags)); |

298 | seterror(ERR_TOOMANYLP); |

299 | return (0); |

300 | } |

301 | |

302 | /* |

303 | * syn1 |

304 | * syn1a |

305 | * syn1a ; syntax |

306 | */ |

307 | static struct command * |

308 | syn1(p1, p2, flags) |

309 | struct wordent *p1, *p2; |

310 | int flags; |

311 | { |

312 | register struct wordent *p; |

313 | register struct command *t; |

314 | int l; |

315 | |

316 | l = 0; |

317 | for (p = p1; p != p2; p = p->next) |

318 | switch (p->word[0]) { |

319 | |

320 | case '(': |

321 | l++; |

322 | continue; |

323 | |

324 | case ')': |

325 | l--; |

326 | continue; |

327 | |

328 | case ';': |

329 | case '\n': |

330 | if (l != 0) |

331 | break; |

332 | t = (struct command *) xcalloc(1, sizeof(*t)); |

333 | t->t_dtyp = NODE_LIST; |

334 | t->t_dcar = syn1a(p1, p, flags); |

335 | t->t_dcdr = syntax(p->next, p2, flags); |

336 | if (t->t_dcdr == 0) |

337 | t->t_dcdr = t->t_dcar, t->t_dcar = 0; |

338 | return (t); |

339 | |

340 | default: |

341 | break; |

342 | } |

343 | return (syn1a(p1, p2, flags)); |

344 | } |

345 | |

346 | /* |

347 | * syn1a |

348 | * syn1b |

349 | * syn1b || syn1a |

350 | */ |

351 | static struct command * |

352 | syn1a(p1, p2, flags) |

353 | struct wordent *p1, *p2; |

354 | int flags; |

355 | { |

356 | register struct wordent *p; |

357 | register struct command *t; |

358 | register int l = 0; |

359 | |

360 | for (p = p1; p != p2; p = p->next) |

361 | switch (p->word[0]) { |

362 | |

363 | case '(': |

364 | l++; |

365 | continue; |

366 | |

367 | case ')': |

368 | l--; |

369 | continue; |

370 | |

371 | case '|': |

372 | if (p->word[1] != '|') |

373 | continue; |

374 | if (l == 0) { |

375 | t = (struct command *) xcalloc(1, sizeof(*t)); |

376 | t->t_dtyp = NODE_OR; |

377 | t->t_dcar = syn1b(p1, p, flags); |

378 | t->t_dcdr = syn1a(p->next, p2, flags); |

379 | t->t_dflg = 0; |

380 | return (t); |

381 | } |

382 | continue; |

383 | |

384 | default: |

385 | break; |

386 | } |

387 | return (syn1b(p1, p2, flags)); |

388 | } |

389 | |

390 | /* |

391 | * syn1b |

392 | * syn2 |

393 | * syn2 && syn1b |

394 | */ |

395 | static struct command * |

396 | syn1b(p1, p2, flags) |

397 | struct wordent *p1, *p2; |

398 | int flags; |

399 | { |

400 | register struct wordent *p; |

401 | register struct command *t; |

402 | register int l = 0; |

403 | |

404 | for (p = p1; p != p2; p = p->next) |

405 | switch (p->word[0]) { |

406 | |

407 | case '(': |

408 | l++; |

409 | continue; |

410 | |

411 | case ')': |

412 | l--; |

413 | continue; |

414 | |

415 | case '&': |

416 | if (p->word[1] == '&' && l == 0) { |

417 | t = (struct command *) xcalloc(1, sizeof(*t)); |

418 | t->t_dtyp = NODE_AND; |

419 | t->t_dcar = syn2(p1, p, flags); |

420 | t->t_dcdr = syn1b(p->next, p2, flags); |

421 | t->t_dflg = 0; |

422 | return (t); |

423 | } |

424 | continue; |

425 | |

426 | default: |

427 | break; |

428 | } |

429 | return (syn2(p1, p2, flags)); |

430 | } |

431 | |

432 | /* |

433 | * syn2 |

434 | * syn3 |

435 | * syn3 | syn2 |

436 | * syn3 |& syn2 |

437 | */ |

438 | static struct command * |

439 | syn2(p1, p2, flags) |

440 | struct wordent *p1, *p2; |

441 | int flags; |

442 | { |

443 | register struct wordent *p, *pn; |

444 | register struct command *t; |

445 | register int l = 0; |

446 | int f; |

447 | |

448 | for (p = p1; p != p2; p = p->next) |

449 | switch (p->word[0]) { |

450 | |

451 | case '(': |

452 | l++; |

453 | continue; |

454 | |

455 | case ')': |

456 | l--; |

457 | continue; |

458 | |

459 | case '|': |

460 | if (l != 0) |

461 | continue; |

462 | t = (struct command *) xcalloc(1, sizeof(*t)); |

463 | f = flags | P_OUT; |

464 | pn = p->next; |

465 | if (pn != p2 && pn->word[0] == '&') { |

466 | f |= P_DIAG; |

467 | t->t_dflg |= F_STDERR; |

468 | } |

469 | t->t_dtyp = NODE_PIPE; |

470 | t->t_dcar = syn3(p1, p, f); |

471 | if (pn != p2 && pn->word[0] == '&') |

472 | p = pn; |

473 | t->t_dcdr = syn2(p->next, p2, flags | P_IN); |

474 | return (t); |

475 | |

476 | default: |

477 | break; |

478 | } |

479 | return (syn3(p1, p2, flags)); |

480 | } |

481 | |

482 | static char RELPAR[] = {'<', '>', '(', ')', '\0'}; |

483 | |

484 | /* |

485 | * syn3 |

486 | * ( syn0 ) [ < in ] [ > out ] |

487 | * word word* [ < in ] [ > out ] |

488 | * KEYWORD ( word* ) word* [ < in ] [ > out ] |

489 | * |

490 | * KEYWORD = (@ exit foreach if set switch test while) |

491 | */ |

492 | static struct command * |

493 | syn3(p1, p2, flags) |

494 | struct wordent *p1, *p2; |

495 | int flags; |

496 | { |

497 | register struct wordent *p; |

498 | struct wordent *lp, *rp; |

499 | register struct command *t; |

500 | register int l; |

501 | Char **av; |

502 | int n, c; |

503 | bool specp = 0; |

504 | |

505 | if (p1 != p2) { |

506 | p = p1; |

507 | again: |

508 | switch (srchx(p->word)) { |

509 | |

510 | case TC_ELSE: |

511 | p = p->next; |

512 | if (p != p2) |

513 | goto again; |

514 | break; |

515 | |

516 | case TC_EXIT: |

517 | case TC_FOREACH: |

518 | case TC_IF: |

519 | case TC_LET: |

520 | case TC_SET: |

521 | case TC_SWITCH: |

522 | case TC_WHILE: |

523 | specp = 1; |

524 | break; |

525 | default: |

526 | break; |

527 | } |

528 | } |

529 | n = 0; |

530 | l = 0; |

531 | for (p = p1; p != p2; p = p->next) |

532 | switch (p->word[0]) { |

533 | |

534 | case '(': |

535 | if (specp) |

536 | n++; |

537 | l++; |

538 | continue; |

539 | |

540 | case ')': |

541 | if (specp) |

542 | n++; |

543 | l--; |

544 | continue; |

545 | |

546 | case '>': |

547 | case '<': |

548 | if (l != 0) { |

549 | if (specp) |

550 | n++; |

551 | continue; |

552 | } |

553 | if (p->next == p2) |

554 | continue; |

555 | if (any(RELPAR, p->next->word[0])) |

556 | continue; |

557 | n--; |

558 | continue; |

559 | |

560 | default: |

561 | if (!specp && l != 0) |

562 | continue; |

563 | n++; |

564 | continue; |

565 | } |

566 | if (n < 0) |

567 | n = 0; |

568 | t = (struct command *) xcalloc(1, sizeof(*t)); |

569 | av = (Char **) xcalloc((size_t) (n + 1), sizeof(Char **)); |

570 | t->t_dcom = av; |

571 | n = 0; |

572 | if (p2->word[0] == ')') |

573 | t->t_dflg = F_NOFORK; |

574 | lp = 0; |

575 | rp = 0; |

576 | l = 0; |

577 | for (p = p1; p != p2; p = p->next) { |

578 | c = p->word[0]; |

579 | switch (c) { |

580 | |

581 | case '(': |

582 | if (l == 0) { |

583 | if (lp != 0 && !specp) |

584 | seterror(ERR_BADPLP); |

585 | lp = p->next; |

586 | } |

587 | l++; |

588 | goto savep; |

589 | |

590 | case ')': |

591 | l--; |

592 | if (l == 0) |

593 | rp = p; |

594 | goto savep; |

595 | |

596 | case '>': |

597 | if (l != 0) |

598 | goto savep; |

599 | if (p->word[1] == '>') |

600 | t->t_dflg |= F_APPEND; |

601 | if (p->next != p2 && eq(p->next->word, STRand)) { |

602 | t->t_dflg |= F_STDERR, p = p->next; |

603 | if (flags & (P_OUT | P_DIAG)) { |

604 | seterror(ERR_OUTRED); |

605 | continue; |

606 | } |

607 | } |

608 | if (p->next != p2 && eq(p->next->word, STRbang)) |

609 | t->t_dflg |= F_OVERWRITE, p = p->next; |

610 | if (p->next == p2) { |

611 | seterror(ERR_MISRED); |

612 | continue; |

613 | } |

614 | p = p->next; |

615 | if (any(RELPAR, p->word[0])) { |

616 | seterror(ERR_MISRED); |

617 | continue; |

618 | } |

619 | if (((flags & P_OUT) && (flags & P_DIAG) == 0) || t->t_drit) |

620 | seterror(ERR_OUTRED); |

621 | else |

622 | t->t_drit = Strsave(p->word); |

623 | continue; |

624 | |

625 | case '<': |

626 | if (l != 0) |

627 | goto savep; |

628 | if (p->word[1] == '<') |

629 | t->t_dflg |= F_READ; |

630 | if (p->next == p2) { |

631 | seterror(ERR_MISRED); |

632 | continue; |

633 | } |

634 | p = p->next; |

635 | if (any(RELPAR, p->word[0])) { |

636 | seterror(ERR_MISRED); |

637 | continue; |

638 | } |

639 | if ((flags & P_HERE) && (t->t_dflg & F_READ)) |

640 | seterror(ERR_REDPAR); |

641 | else if ((flags & P_IN) || t->t_dlef) |

642 | seterror(ERR_INRED); |

643 | else |

644 | t->t_dlef = Strsave(p->word); |

645 | continue; |

646 | |

647 | savep: |

648 | if (!specp) |

649 | continue; |

650 | default: |

651 | if (l != 0 && !specp) |

652 | continue; |

653 | if (seterr == 0) |

654 | av[n] = Strsave(p->word); |

655 | n++; |

656 | continue; |

657 | } |

658 | } |

659 | if (lp != 0 && !specp) { |

660 | if (n != 0) |

661 | seterror(ERR_BADPLPS); |

662 | t->t_dtyp = NODE_PAREN; |

663 | t->t_dspr = syn0(lp, rp, P_HERE); |

664 | } |

665 | else { |

666 | if (n == 0) |

667 | seterror(ERR_NULLCOM); |

668 | t->t_dtyp = NODE_COMMAND; |

669 | } |

670 | return (t); |

671 | } |

672 | |

673 | void |

674 | freesyn(t) |

675 | register struct command *t; |

676 | { |

677 | register Char **v; |

678 | |

679 | if (t == 0) |

680 | return; |

681 | switch (t->t_dtyp) { |

682 | |

683 | case NODE_COMMAND: |

684 | for (v = t->t_dcom; *v; v++) |

685 | xfree((ptr_t) * v); |

686 | xfree((ptr_t) (t->t_dcom)); |

687 | xfree((ptr_t) t->t_dlef); |

688 | xfree((ptr_t) t->t_drit); |

689 | break; |

690 | case NODE_PAREN: |

691 | freesyn(t->t_dspr); |

692 | xfree((ptr_t) t->t_dlef); |

693 | xfree((ptr_t) t->t_drit); |

694 | break; |

695 | |

696 | case NODE_AND: |

697 | case NODE_OR: |

698 | case NODE_PIPE: |

699 | case NODE_LIST: |

700 | freesyn(t->t_dcar), freesyn(t->t_dcdr); |

701 | break; |

702 | default: |

703 | break; |

704 | } |

705 | xfree((ptr_t) t); |

706 | } |

**Note:**See TracBrowser for help on using the repository browser.