4.4BSD/usr/src/usr.bin/pascal/pdx/command/grammar.y

%{
/*-
 * Copyright (c) 1982, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
static char sccsid[] = "@(#)grammar.y	8.1 (Berkeley) 6/6/93";
#endif /* not lint */

/*
 * yacc grammar for debugger commands
 */

#include "defs.h"
#include "command.h"
#include "sym.h"
#include "symtab.h"
#include "tree.h"
#include "process.h"
#include "source.h"

%}

%term ALIAS ASSIGN CALL CHFILE
%term CONT DUMP EDIT
%term GRIPE HELP LIST NEXT
%term QUIT REMAKE PRINT
%term RUN SH SOURCE
%term STATUS STEP
%term STOP STOPI TRACE TRACEI
%term DELETE
%term WHATIS WHICH WHERE
%term XI XD

%term AT IN IF
%term FILENAME
%term INT REAL NAME STRING
%term DIV MOD
%term AND OR NOT

%binary '<' '=' '>' IN
%left '+' '-' OR '|'
%left UNARYSIGN
%left '*' '/' DIV MOD AND '&'
%left NOT

%union {
	SYM *y_sym;
	NODE *y_node;
	int y_int;
	OP y_op;
	long y_long;
	double y_real;
	char *y_string;
	BOOLEAN y_bool;
};

%type <y_int> trace TRACE TRACEI stop STOP STOPI
%type <y_long> INT
%type <y_real> REAL
%type <y_op> addop mulop relop
%type <y_string> STRING FILENAME SH opt_filename
%type <y_sym> NAME
%type <y_node> command rcommand what where opt_arglist opt_cond
%type <y_node> exp_list exp boolean_exp term constant
%type <y_node> line_list line_number address_list
%%
input:
	input command_nl
{
		prompt();
}
|	/* empty */
;
command_nl:
	command_line '\n'
|	'\n'
;

/*
 * There are two kinds of commands, those that can be redirected
 * and those that can't.
 */

command_line:
	command
{
		eval($1);
}
|	rcommand
{
		eval($1);
}
|	rcommand '>' FILENAME
{
		setout($3);
		eval($1);
		unsetout();
}
|	SH
{
		shell($1);
}
|	run args
{
		run();
}
;
run:
	RUN
{
		arginit();
}
;
args:
	arg args
|	/* empty */
;
arg:
	FILENAME
{
		newarg($1);
}
|	'<' FILENAME
{
		inarg($2);
}
|	'>' FILENAME
{
		outarg($2);
}
;
command:
	ASSIGN term exp
{
		$$ = build(O_ASSIGN, $2, $3);
}
|	CHFILE opt_filename
{
		$$ = build(O_CHFILE, $2);
}
|	CONT
{
		$$ = build(O_CONT);
}
|	LIST line_list
{
		$$ = build(O_LIST, $2);
}
|	LIST NAME
{
		$$ = build(O_LIST, build(O_NAME, $2));
}
|	NEXT
{
		$$ = build(O_NEXT);
}
|	PRINT exp_list
{
		$$ = build(O_PRINT, $2);
}
|	QUIT
{
		quit(0);
}
|	STEP
{
		$$ = build(O_STEP);
}
|	stop where opt_cond
{
		$$ = build($1, NIL, $2, $3);
}
|	stop what opt_cond
{
		$$ = build($1, $2, NIL, $3);
}
|	stop IF boolean_exp
{
		$$ = build($1, NIL, NIL, $3);
}
|	trace what where opt_cond
{
		$$ = build($1, $2, $3, $4);
}
|	trace where opt_cond
{
		$$ = build($1, NIL, $2, $3);
}
|	trace what opt_cond
{
		$$ = build($1, $2, NIL, $3);
}
|	trace opt_cond
{
		$$ = build($1, NIL, NIL, $2);
}
|	DELETE INT
{
		$$ = build(O_DELETE, $2);
}
|	WHATIS term
{
		$$ = build(O_WHATIS, $2);
}
|	WHICH NAME
{
		$$ = build(O_WHICH, $2);
}
|	WHERE
{
		$$ = build(O_WHERE);
}
|	XI address_list
{
		$$ = build(O_XI, $2);
}
|	XD address_list
{
		$$ = build(O_XD, $2);
}
;
rcommand:
	ALIAS FILENAME opt_filename
{
		$$ = build(O_ALIAS, $2, $3);
}
|	ALIAS
{
		$$ = build(O_ALIAS, NIL, NIL);
}
|	CALL term opt_arglist
{
		$$ = build(O_CALL, $2, $3);
}
|	EDIT opt_filename
{
		$$ = build(O_EDIT, $2);
}
|	DUMP
{
		$$ = build(O_DUMP);
}
|	GRIPE
{
		$$ = build(O_GRIPE);
}
|	HELP
{
		$$ = build(O_HELP);
}
|	REMAKE
{
		$$ = build(O_REMAKE);
}
|	SOURCE FILENAME
{
		$$ = build(O_SOURCE, $2);
}
|	STATUS
{
		$$ = build(O_STATUS);
}
;
trace:
	TRACE
{
		$$ = O_TRACE;
}
|	TRACEI
{
		$$ = O_TRACEI;
}
;
stop:
	STOP
{
		$$ = O_STOP;
}
|	STOPI
{
		$$ = O_STOPI;
}
;
what:
	exp
|	FILENAME line_number
{
		$$ = build(O_QLINE, $1, $2);
}
;
where:
	IN term
{
		$$ = $2;
}
|	AT line_number
{
		$$ = build(O_QLINE, cursource, $2);
}
|	AT FILENAME line_number
{
		$$ = build(O_QLINE, $2, $3);
}
;
opt_filename:
	/* empty */
{
		$$ = NIL;
}
|	FILENAME
;
opt_arglist:
	/* empty */
{
		$$ = NIL;
}
|	'(' exp_list ')'
{
		$$ = $2;
}
;
line_list:
	/* empty */
{
		NODE *first, *last;

		first = build(O_LCON, (long) 1);
		last = build(O_LCON, (long) lastlinenum);
		$$ = build(O_COMMA, first, last);
}
|	line_number
{
		$$ = build(O_COMMA, $1, $1);
}
|	line_number ',' line_number
{
		$$ = build(O_COMMA, $1, $3);
}
;
line_number:
	INT
{
		$$ = build(O_LCON, $1);
}
|	'$'
{
		$$ = build(O_LCON, (long) lastlinenum);
}
;
address_list:
	exp
{
		$$ = build(O_COMMA, $1, $1);
}
|	exp ',' exp
{
		$$ = build(O_COMMA, $1, $3);
}
;
opt_cond:
	/* empty */
{
		$$ = NIL;
}
|	IF boolean_exp
{
		$$ = $2;
}
;
exp_list:
	exp
{
		$$ = build(O_COMMA, $1, NIL);
}
|	exp ',' exp_list
{
		$$ = build(O_COMMA, $1, $3);
}
;
exp:
	term
{
		$$ = build(O_RVAL, $1);
}
|	term '(' exp_list ')'
{
		$$ = build(O_CALL, $1, $3);
}
|	constant
|	'+' exp %prec UNARYSIGN
{
		$$ = $2;
}
|	'-' exp %prec UNARYSIGN
{
		$$ = build(O_NEG, $2);
}
|	exp addop exp %prec '+'
{
		$$ = build($2, $1, $3);
}
|	exp mulop exp %prec '*'
{
		$$ = build($2, $1, $3);
}
|	exp relop exp %prec '<'
{
		$$ = build($2, $1, $3);
}
|	'(' exp ')'
{
		$$ = $2;
}
;
boolean_exp:
	exp
{
		chkboolean($$ = $1);
}
;
term:
	NAME
{
		$$ = build(O_NAME, $1);
}
|	AT
{
		SYM *s;

		s = st_lookup(symtab, "at");
		if (s == NIL) {
			error("\"at\" is not defined");
		}
		$$ = build(O_NAME, s);
}
|	term '[' exp_list ']'
{
		$$ = subscript($1, $3);
}
|	term '.' NAME
{
		$$ = dot($1, $3);
}
|	term '^'
{
		$$ = build(O_INDIR, $1);
}
;
constant:
	INT
{
		$$ = build(O_LCON, $1);
}
|	REAL
{
		$$ = build(O_FCON, $1);
}
|	STRING
{
		$$ = build(O_SCON, $1);
}
;
addop:
	'+'
{
		$$ = O_ADD;
}
|	'-'
{
		$$ = O_SUB;
}
|	OR
{
		$$ = O_OR;
}
|	'|'
{
		$$ = O_OR;
}
;
mulop:
	'*'
{
		$$ = O_MUL;
}
|	'/'
{
		$$ = O_DIVF;
}
|	DIV
{
		$$ = O_DIV;
}
|	MOD
{
		$$ = O_MOD;
}
|	AND
{
		$$ = O_AND;
}
|	'&'
{
		$$ = O_AND;
}
;
relop:
	'<'
{
		$$ = O_LT;
}
|	'<' '='
{
		$$ = O_LE;
}
|	'>'
{
		$$ = O_GT;
}
|	'>' '='
{
		$$ = O_GE;
}
|	'='
{
		$$ = O_EQ;
}
|	'<' '>'
{
		$$ = O_NE;
}
;
%%

/*
 * parser error handling
 */

yyerror(s)
char *s;
{
	if (strcmp(s, "syntax error") == 0) {
		error("bad command syntax");
	} else {
		error(s);
	}
}

/*
 * In recovering from an error we gobble input up to a newline.
 */

gobble()
{
	register int t;

	if (!nlflag) {
		while ((t = yylex()) != '\n' && t != 0);
	}
}