File:  [MW Coherent from dump] / coherent / d / bin / sh / sh.y
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * sh/sh.y
 * The Bourne shell.
 * This shell is dedicated to Ciaran Gerald Aidan O'Donnell.
 * May he live a thousand minutes (long enough to fix up YACC).
 * It is also dedicated to Steve Bourne.
 * May he live a thousand seconds.
 */
%{
#include "sh.h"

#define YYERROR	{ yyerrflag=1; goto YYerract; }

extern	NODE	*node();
%}

%union {
	NODE	*yu_node;
	char	*yu_strp;
	int	yu_nval;
}

%token _ANDF
%token _ASGN
%token _CASE
%token _CBRAC
%token _DO
%token _DONE
%token _DSEMI
%token _ELIF
%token _ELSE
%token _ESAC
%token _FI
%token _FOR
%token _IF
%token _IN
%token _IORS
%token _NAME
%token _NULL
%token _OBRAC
%token _ORF
%token _THEN
%token _UNTIL
%token _WHILE

%type <yu_node>	arg		arg_list	case_line	case_list
%type <yu_node>	cmd		cmd_line	cmd_list	cmd_seq
%type <yu_node>	control		do_list		else_part	in_name_list
%type <yu_node>	logical_cmd	name_list	opt_cmd_seq	pattern_list
%type <yu_node>	pipe_cmd	sub_shell

%type <yu_strp>	asgn		name		redirect

%type <yu_nval> whuntile

%%

session:
	session cmd_line
|
;

cmd_line:
	'\n' {
		sesp->s_node = NULL;
		reset(RCMD);
		NOTREACHED;
	}
|
	cmd_list '\n' {
		sesp->s_node = $1;
		reset(errflag ? RERR : RCMD);
		NOTREACHED;
	}
|	error '\n' {
		keyflush();
		keyflag = 1;
		reset(RERR);
		NOTREACHED;
	}
;

if:	_IF optnls ;

then:	_THEN optnls ;

elif:	_ELIF optnls ;

else:	_ELSE optnls ;

whuntile:	_WHILE optnls {	$$ = NWHILE;	}
|	_UNTIL optnls {	$$ = NUNTIL;	}
;

do:	_DO optnls | _DO ';' optnls ;

in:	_IN | _IN sep ;

oror:	_ORF optnls;

andand:	_ANDF optnls;

or:	'|' optnls;

oparen:	'(' optnls ;

obrack:	_OBRAC optnls ;

cparen:	')' optnls ;

dsemi:	_DSEMI optnls ;

cmd_list:
	logical_cmd {
		$$ = $1;
	}
|	logical_cmd '&' {
		$$ = node(NBACK, $1, NULL);
	}
|	logical_cmd ';' {
		$$ = $1;
	}
|	logical_cmd '&' cmd_list {
		$$ = node(NBACK, $1, $3);
	}
|	logical_cmd ';' cmd_list {
		$$ = node(NLIST, $1, $3);
	}
;

logical_cmd:
	pipe_cmd {
		$$ = $1;
	}
|	pipe_cmd oror logical_cmd {
		$$ = node(NORF, $1, $3);
	}
|	pipe_cmd andand logical_cmd {
		$$ = node(NANDF, $1, $3);
	}
;

pipe_cmd:
	cmd or pipe_cmd {
		$$ = node(NPIPE, $1, $3);
	}
|	cmd {
		$$ = $1;
	}
;

cmd:
	arg_list_init arg_list {
		$$ = node(NCOMS, $2, NULL);
		keypop();
	}
;

arg_list_init:
	{
		keypush();
		keyflag = 1;
	}
;

arg_list:
	arg arg_list {
		if (($1->n_type == NCTRL && $2->n_type == NARGS)
		 || ($1->n_type == NARGS && $2->n_type == NCTRL)) {
			YYERROR;
		}
		($$ = $1)->n_next = $2;
	}
|	arg {
		$$ = $1;
	}
;

arg:
	redirect {
		$$ = node(NIORS, $1, NULL);
	}
|	name {
		$$ = node(NARGS, $1, NULL);
		keyflag = 0;
	}
|	asgn {
		$$ = node(NASSG, $1, NULL);
	}
|	control {
		if (!keyflag) {
			YYERROR;
		}
		$$ = node(NCTRL, $1, NULL);
		keyflag = 0;
	}
;

redirect:	_IORS {
		$$ = duplstr(strt, 0);
	}
;

name:	_NAME {
		$$ = duplstr(strt, 0);
	}
;

asgn:	_ASGN {
		$$ = duplstr(strt, 0);
	}
;

control:
	_FOR name in_name_list sep do_list _DONE {
		$$ = node(NFOR, $2, node(NFOR2, $3, node(NLIST, $5, NULL)));
		$$->n_next->n_next->n_next = $$->n_next;
	}
|	_FOR name in_name_list do_list _DONE {
		$$ = node(NFOR, $2, node(NFOR2, $3, node(NLIST, $4, NULL)));
		$$->n_next->n_next->n_next = $$->n_next;
	}
|	_CASE name sep in case_list _ESAC {
		$$ = node(NCASE, $2, $5);
	}
|	_CASE name in case_list _ESAC {
		$$ = node(NCASE, $2, $4);
	}
|	whuntile cmd_seq do_list _DONE {
		$$ = node($1, $2, node(NLIST, $3, NULL));
		$$->n_next->n_next = $$;
	}
|	if cmd_seq then opt_cmd_seq else_part _FI {
		$$ = node(NIF, node(NNULL, $2, $4), $5);
	}
|	oparen opt_cmd_seq ')' {
		$$ = node(NPARN, $2, NULL);
	}
|	obrack opt_cmd_seq _CBRAC {
		$$ = node(NBRAC, $2, NULL);
	}
;

in_name_list:
	_IN name_list {
		$$ = $2;
	}
|	{
		$$ = node(NARGS, "\"$@\"", NULL);
	}
;

name_list:
	name name_list {
		$$ = node(NARGS, $1, $2);
	}
|	{
		$$ = NULL;
	}
;

case_list:
	case_line dsemi case_list {
		register NODE *np;

		for (np=$1; np->n_next; np=np->n_next)
			;
		np->n_next = $3;
		$$ = $1;
	}
|	case_line {
		$$ = $1;
	}
|	{
		$$ = NULL;
	}
;

case_line:
	pattern_list cparen opt_cmd_seq {
		$$ = node(NCASE2, $3, $1);
	}
;

pattern_list:
	name '|' pattern_list {
		$$ = node(NCASE3, $1, $3);
	}
|	name {
		$$ = node(NCASE3, $1, NULL);
	}
;

do_list:
	do opt_cmd_seq {
		$$ = $2;
	}
|	{
		$$ = NULL;
	}
;

else_part:
	elif cmd_seq then opt_cmd_seq else_part {
		$$ = node(NIF, node(NNULL, $2, $4), $5);
	}
|	else opt_cmd_seq {
		$$ = node(NELSE, $2, NULL);
	}
|	{
		$$ = NULL;
	}
;

opt_cmd_seq:
	cmd_seq {
		$$ = $1;
	}
|
	{
		$$ = NULL;
	}
;

cmd_seq:
	cmd_list nls cmd_seq {
		$$ = node(NLIST, $1, $3);
	}
|	cmd_list optnls {
		$$ = $1;
	}
;

sep:	nls
|	';'
|	';' nls
;

optnls:	nls
|
;

nls:	'\n'
|	nls '\n'
;

%%
/*
 * Create a node.
 */
NODE *
node(type, auxp, next)
NODE *auxp, *next;
{
	register NODE *np;

	np = (NODE *) balloc(sizeof (NODE));
	np->n_type = type;
	np->n_auxp = auxp;
	np->n_next = next;
	return np;
}

#define NBPC 8
#define NKEY 8
static char keys[NKEY] = { 0 };
static int  keyi = NKEY * NBPC;

keyflush()
{
	register char *kp;

	for (kp = keys+NKEY; kp > keys; *--kp = 0)
		;
	keyi = NKEY * NBPC;
}

keypop()
{
	register char	*kp;
	register int	km;

	if ((km = keyi++) >= NKEY * NBPC) {
		panic(11);
		NOTREACHED;
	}
	kp = keys + (km / NBPC);
	km = 1 << (km %= NBPC);
	keyflag = (*kp & km) ? 1 : 0;
	*kp &= ~km;
}

keypush()
{
	register char	*kp;
	register int	km;

	if ((km = --keyi) < 0) {
		panic(12);
		NOTREACHED;
	}
	if (keyflag) {
		kp = keys + (km / NBPC);
		km = 1 << (km %= NBPC);
		*kp |= km;
	}
}
/*
 * The following fragments might implement named pipes.
 * The token declaration goes in the header.
 * The nopen production should go with the others of its ilk.
 * The production fragment goes into arg:
%token _NOPEN _NCLOSE
nopen:	_NOPEN optnls ;

|	nopen pipe_cmd ')' {
		$$ = node(NRPIPE, $2, NULL);
	}
|	oparen pipe_cmd _NCLOSE {
		$$ = node(NWPIPE, $2, NULL);
	}
 *
 */

/* end of sh/sh.y */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.