/*
 * 5799-WZQ (C) COPYRIGHT = NONE
 * LICENSED MATERIALS - PROPERTY OF IBM
 */
/* $Header:rpc_parse.c 12.0$ */
/* $ACIS:rpc_parse.c 12.0$ */
/* $Source: /ibm/acis/usr/src/nfs/usr.bin/rpcgen/RCS/rpc_parse.c,v $ */

#ifndef lint
static char *rcsid = "$Header:rpc_parse.c 12.0$";
#endif

#include <sys/nfs_defines.h>

/* 87/08/14 @(#)rpc_parse.c	1.2 3.2/4.3 NFSSRC */
#ifndef lint 
static char sccsid[] = "@(#)rpc_parse.c 1.1 86/09/25 (C) 1986 SMI";
#endif
/*
 *
 * NFSSRC 3.2/4.3 for the VAX*
 * Copyright (C) 1987 Sun Microsystems, Inc.
 * 
 * (*)VAX is a trademark of Digital Equipment Corporation
 *
 */

/* 
 * rpc_parse.c, Parser for the RPC protocol compiler
 * Copyright (C) 1986, 1987 Sun Microsystems, Inc.
 */

#include <stdio.h> 
#include "rpc_util.h"
#include "rpc_scan.h"
#include "rpc_parse.h"

/*
 * return the next definition you see
 */
definition *
get_definition()
{
	definition *defp;
	token tok;


	defp = ALLOC(definition);
	get_token(&tok);
	switch (tok.kind) {
	case TOK_STRUCT:
		def_struct(defp);
		break;
	case TOK_UNION:
		def_union(defp);
		break;
	case TOK_TYPEDEF:
		def_typedef(defp);
		break;
	case TOK_ARRAY:
		def_array(defp);
		break;
	case TOK_ENUM:
		def_enum(defp);
		break;
	case TOK_PROGRAM:
		def_program(defp);	
		break;
	case TOK_EOF:
		return(NULL);	
		break;
	default:
		error("definition keyword expected");
	}
	scan(TOK_SEMICOLON,&tok);
	isdefined(defp);
	return(defp);
}

static 
isdefined(defp)
	definition *defp;
{
	STOREVAL(&defined,defp); 
}


static
def_struct(defp)
	definition *defp;
{
	token tok;
	declaration dec;
	decl_list *decls;
	decl_list **tailp;

	defp->def_kind = DEF_STRUCT;

	scan(TOK_IDENT,&tok);
	defp->def_name = tok.str;
	scan(TOK_LBRACE,&tok);
	tailp = &defp->def.st.decls;
	do {
		get_declaration(&dec,DEF_STRUCT);
		decls = ALLOC(decl_list);
		decls->decl = dec;
		*tailp = decls;
		tailp = &decls->next;
		scan(TOK_SEMICOLON,&tok);
		peek(&tok);	
	} while (tok.kind != TOK_RBRACE);
	get_token(&tok);	
	*tailp = NULL;	
}

static
def_program(defp)
	definition *defp;
{
	token tok;
	version_list *vlist;
	version_list **vtailp;
	proc_list *plist;
	proc_list **ptailp;
	
	defp->def_kind = DEF_PROGRAM;
	scan(TOK_IDENT,&tok);
	defp->def_name = tok.str;
	scan(TOK_LBRACE,&tok);
	vtailp = &defp->def.pr.versions;
	scan(TOK_VERSION,&tok);
	do {
		scan(TOK_IDENT,&tok);
		vlist = ALLOC(version_list);
		vlist->vers_name = tok.str;
		scan(TOK_LBRACE,&tok);
		ptailp = &vlist->procs;
		do {
			plist = ALLOC(proc_list);
			get_type(&plist->res_prefix,&plist->res_type,DEF_PROGRAM);
			if (streq(plist->res_type,"string") || 
					streq(plist->res_type,"opaque")) {
				error("illegal result type");
			}
			scan(TOK_IDENT,&tok);
			plist->proc_name = tok.str;
			scan(TOK_LPAREN,&tok);
			get_type(&plist->arg_prefix,&plist->arg_type,DEF_PROGRAM);
			if (streq(plist->arg_type,"string") || 
					streq(plist->arg_type,"opaque")) {
				error("illegal argument type");
			}
			scan(TOK_RPAREN,&tok);
			scan(TOK_EQUAL,&tok);
			scan_num(&tok);
			scan(TOK_SEMICOLON,&tok);
			plist->proc_num = tok.str;
			*ptailp = plist;
			ptailp = &plist->next;
			peek(&tok);
		} while (tok.kind != TOK_RBRACE);
		*vtailp = vlist;
		vtailp = &vlist->next;
		scan(TOK_RBRACE,&tok);
		scan(TOK_EQUAL,&tok);
		scan_num(&tok);
		vlist->vers_num = tok.str;
		scan(TOK_SEMICOLON,&tok);
		scan2(TOK_VERSION,TOK_RBRACE,&tok);
	} while (tok.kind == TOK_VERSION);
	scan(TOK_EQUAL, &tok);
	scan_num(&tok);
	defp->def.pr.prog_num = tok.str;
	*vtailp = NULL;
}
	
static	
def_enum(defp)
	definition *defp;
{
	token tok;
	enumval_list *elist;
	enumval_list **tailp;

	defp->def_kind = DEF_ENUM;
	scan(TOK_IDENT,&tok);
	defp->def_name = tok.str;
	scan(TOK_LBRACE,&tok);
	tailp = &defp->def.en.vals;
	do {
		scan(TOK_IDENT,&tok);
		elist = ALLOC(enumval_list);
		elist->name = tok.str;
		elist->assignment = NULL;
		scan3(TOK_COMMA,TOK_RBRACE,TOK_EQUAL,&tok);	
		if (tok.kind == TOK_EQUAL) {
			scan_num(&tok);
			elist->assignment = tok.str;
			scan2(TOK_COMMA,TOK_RBRACE,&tok);
		}
		*tailp = elist;
		tailp = &elist->next;
	} while (tok.kind != TOK_RBRACE);
	*tailp = NULL;
}
	
static
def_array(defp)
	definition *defp;
{
	token tok;
	declaration dec;

	defp->def_kind = DEF_ARRAY;
	scan(TOK_IDENT,&tok);
	defp->def_name = tok.str;
	scan(TOK_LBRACE,&tok);
	get_declaration(&dec,DEF_ARRAY);
	if (! streq(dec.type,"u_int")) {
		error("array length must be of type unsigned");
	}
	if (dec.rel != REL_ALIAS) {
		error("array length may not be pointer or vector");
	}
	scan(TOK_SEMICOLON,&tok);
	defp->def.ar.len_name = dec.name;
	get_declaration(&dec,DEF_ARRAY);
	if (dec.rel != REL_VECTOR) {
		error("expected array declaration");
	}
	if (streq(dec.type,"string")) {
		error("string declarations don't make sense here");
	}
	scan(TOK_SEMICOLON,&tok);
	defp->def.ar.array_prefix = dec.prefix;
	defp->def.ar.array_type = dec.type;
	defp->def.ar.array_name = dec.name;
	defp->def.ar.array_max = dec.array_max;
	scan(TOK_RBRACE,&tok);
}



static
def_union(defp)
	definition *defp;
{ 
	token tok;
	declaration dec;
	case_list *cases;
	case_list **tailp;

	defp->def_kind = DEF_UNION;
	scan(TOK_IDENT,&tok);
	defp->def_name = tok.str;
	scan(TOK_SWITCH,&tok);
	scan(TOK_LPAREN,&tok);
	get_declaration(&dec,DEF_UNION);
	defp->def.un.enum_decl = dec;
	tailp = &defp->def.un.cases;
	scan(TOK_RPAREN,&tok);
	scan(TOK_LBRACE,&tok);
	scan(TOK_CASE, &tok);
	while (tok.kind == TOK_CASE) {
		scan(TOK_IDENT,&tok);
		cases = ALLOC(case_list);
		cases->case_name = tok.str;
		scan(TOK_COLON,&tok);
		get_declaration(&dec,DEF_UNION);
		cases->case_decl = dec;
		*tailp = cases;
		tailp = &cases->next;
		scan(TOK_SEMICOLON,&tok);
		scan3(TOK_CASE,TOK_DEFAULT,TOK_RBRACE,&tok);
	}
	*tailp = NULL;
	if (tok.kind == TOK_DEFAULT) {
		scan(TOK_COLON,&tok);
		get_declaration(&dec,DEF_UNION);
		defp->def.un.default_decl =  ALLOC(declaration);
		*defp->def.un.default_decl = dec;
		scan(TOK_SEMICOLON,&tok);
		scan(TOK_RBRACE,&tok);
	}
}


static
def_typedef(defp)
	definition *defp;
{ 
	declaration dec;

	defp->def_kind = DEF_TYPEDEF;
	get_declaration(&dec,DEF_TYPEDEF);
	defp->def_name = dec.name;
	defp->def.ty.old_prefix = dec.prefix;
	defp->def.ty.old_type = dec.type;
	defp->def.ty.rel = dec.rel;
	defp->def.ty.array_max = dec.array_max;
}


static
get_declaration(dec,dkind)
	declaration *dec;
	defkind dkind;
{
	token tok;

	get_type(&dec->prefix,&dec->type,dkind);
	dec->rel = REL_ALIAS;
	scan2(TOK_STAR,TOK_IDENT,&tok);
	if (tok.kind == TOK_STAR) {
		dec->rel = REL_POINTER;
		scan(TOK_IDENT,&tok);
	}
	dec->name = tok.str; 
	if (peekscan(TOK_LBRACKET,&tok)) {
		if (dec->rel == REL_POINTER) {
			error("no array-of-pointer declarations -- use typedef");
		}
		dec->rel = REL_VECTOR;
		if (streq(dec->type,"string") && peekscan(TOK_RBRACKET,&tok)) {
			dec->array_max = NULL; 	/* means unspecified */
		} else {	
			dec->rel = REL_VECTOR;
			scan_num(&tok);	
			dec->array_max = tok.str;
			scan(TOK_RBRACKET,&tok);
		}
	}
	if (streq(dec->type,"opaque") || streq(dec->type,"string")) {
		if (dec->rel != REL_VECTOR) {
			error("vector declaration expected");
		}
	} else if (streq(dec->type,"void")) {
		if (dec->rel != REL_ALIAS) {
			error("no vector-of-void or pointer-to-void declarations");
		}
	}
}


static
get_type(prefixp,typep, dkind)
	char **prefixp;
	char **typep;
	defkind dkind;
{
	token tok;

	*prefixp = NULL; 
	get_token(&tok);
	switch (tok.kind) {
	case TOK_IDENT:
		*typep = tok.str;
		break;
	case TOK_STRUCT:
	case TOK_ENUM:
	case TOK_ARRAY:
	case TOK_UNION:
		*prefixp = tok.str;
		scan(TOK_IDENT,&tok);	
		*typep = tok.str;
		break;
	case TOK_UNSIGNED:
		unsigned_dec(typep);
		break;
	case TOK_SHORT:
		*typep = "short"; 
		(void) peekscan(TOK_INT,&tok);
		break;
	case TOK_LONG:
		*typep = "long"; 
		(void) peekscan(TOK_INT,&tok);
		break;
	case TOK_VOID:
		if (dkind != DEF_UNION && dkind != DEF_PROGRAM) {
			error("voids allowed only inside union and program definitions");
		}
		*typep = tok.str;
		break;
	case TOK_STRING:
	case TOK_OPAQUE:
	case TOK_CHAR:
	case TOK_INT:
	case TOK_FLOAT:
	case TOK_DOUBLE:
	case TOK_BOOL:
		*typep = tok.str;
		break;	
	default:
		error("expected type specifier");
	}
}


static
unsigned_dec(typep)
	char **typep;
{
	token tok;

	peek(&tok);
	switch (tok.kind) {
	case TOK_CHAR:
		get_token(&tok);
		*typep = "u_char";
		break;
	case TOK_SHORT:
		get_token(&tok);
		*typep = "u_short";
		(void) peekscan(TOK_INT,&tok);
		break;
	case TOK_LONG:
		get_token(&tok);
		*typep = "u_long";
		(void) peekscan(TOK_INT,&tok);
		break;
	case TOK_INT:
		get_token(&tok);
		*typep = "u_int";
		break;
	default:
		*typep = "u_int";
		break;
	}
}

/* 
 * NFSSRC 3.2/4.3 for the VAX*
 * Copyright (C) 1987 Sun Microsystems, Inc.
 * 
 * (*)VAX is a trademark of Digital Equipment Corporation
 */
