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

/*
 * 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 _PARENS
%token _RET
%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_node>	command		simple_command	redirect_list	cmd_prefix
%type <yu_node>	cmd_word	cmd_suffix	cmd_name	redirect_list
%type <yu_node>	asgn_node	redirect_node	name_node
%type <yu_node>	function_definition	compound_command
%type <yu_node>	non_keyword_name

%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;
	}
;

/*
 * In the original grammar, no distinction between simple command and compound
 * commands was made. This, along with the right-recursive formulation of the
 * command grammar, created a need for lookahead that defeated the complex
 * machinery for context-sensitive lexing that is required.
 */

cmd:	turn_on_keywords command {
		$$ = $2;
		keypop ();
	}
;

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

command:
	simple_command {
		$$ = node (NCOMS, $1, NULL);
	}
|	compound_command {
		$$ = node (NCOMS, $1, NULL);
	}
|	compound_command redirect_list {
		$$ = node (NCOMS, $1->n_next = $2, NULL);
	}
|	function_definition {
		$$ = node (NCOMS, $1, NULL);
	}
|	_RET name {
		$$ = node (NRET, $2, NULL);
	}
|	_RET {
		$$ = node (NRET, "", NULL);
	}
;

compound_command:
	control {
		$$ = node (NCTRL, $1, NULL);
	}
;
	
function_definition:
	name _PARENS optnls obrack cmd_seq _CBRAC  {
		$$ = node (NCTRL, node (NFUNC, $1, $5), NULL);
	}
;

redirect_list:
	redirect_node {
		$$ = $1;
	}
|	redirect_list redirect_node {
		($$ = $1)->n_next = $2;
	}
;

simple_command:
	cmd_prefix cmd_word cmd_suffix {
		(($$ = $1)->n_next = $2)->n_next = $3;
	}
|	cmd_prefix cmd_word {
		($$ = $1)->n_next = $2;
	}
|	cmd_prefix {
		$$ = $1;
	}
|	cmd_name cmd_suffix {
		($$ = $1)->n_next = $2;
	}
|	cmd_name {
		$$ = $1;
	}
;

cmd_prefix:
	redirect_node {
		$$ = $1;
	}
|	redirect_node cmd_prefix {
		($$ = $1)->n_next = $2;
	}
|	asgn_node {
		$$ = $1;
	}
|	asgn_node cmd_prefix {
		($$ = $1)->n_next = $2;
	}
;

cmd_name:
	name_node {
		$$ = $1;
		keyflag = 0;
	}
;

cmd_word:
	name_node {
		$$ = $1;
		keyflag = 0;
	}
;

/*
 * The main part of this shell has some silliness with assignments and some
 * flag called '-k'. To support this, we allow assignments after the command
 * name and code elsewhere turns them back into parameters... it seems
 * preferable to do it here, but because of the '-k' thing we'll just
 * accept them.
 */

cmd_suffix:
	redirect_node {
		$$ = $1;
	}
|	redirect_node cmd_suffix {
		($$ = $1)->n_next = $2;
	}
|	non_keyword_name {
		$$ = $1;
	}
|	non_keyword_name cmd_suffix {
		($$ = $1)->n_next = $2;
	}
|	asgn_node {
		$$ = $1;
	}
|	asgn_node cmd_suffix {
		($$ = $1)->n_next = $2;
	}
;

non_keyword_name:
	non_keyword_string {
		$$ = node (NARGS, duplstr (strt, 0), NULL);
	}
;

/*
 * Many of the following cause S/R conflicts. This reflects the fact that the
 * decision about whether to recognise a token in a given place needs some
 * extra disambiguation or not. In all cases, the correct result is to shift
 * (treating the reserved word as a normal word), which is the default.
 */
non_keyword_string:
	_NAME
|	_CASE
|	_DO
|	_DONE
|	_ELIF
|	_ELSE
|	_ESAC
|	_FI
|	_FOR
|	_IF
|	_IN
|	_RET
|	_THEN
|	_UNTIL
|	_WHILE
;
	
/*
 * Replaced by detailed cases above.
cmd:
	arg_list_init arg_list {
		$$ = node(NCOMS, $2, NULL);
		keypop();
	}
|	_RET name {
		$$ = node(NRET, $2, NULL);
	}
|	_RET {
		$$ = node(NRET, "", NULL);
	}
;

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 {
		$$ = $1;
	}
|	name_node {
		$$ = $1;
		keyflag = 0;
	}
|	asgn_node {
		$$ = $1;
	}
|	control {
		if (!keyflag) {
			YYERROR;
		}
		$$ = node(NCTRL, $1, NULL);
		keyflag = 0;
	}
;
*/

/*
 * The form of the following productions arranges for the contents of the
 * global "strt" to be duplicated ASAP, hopefully before lookahead gets
 * involved.
 */

redirect_node:	redirect {
		$$ = node (NIORS, $1, NULL);
	}
;

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

name_node: name {
		$$ = node (NARGS, $1, NULL);
	}
;

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


asgn_node: asgn {
		$$ = node (NASSG, $1, NULL);
	}
;

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);
	}
 *
 */

unix.superglobalmegacorp.com

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