/************************************************************************/
/*                                                                      */
/* Copyright (c) 1988 -                                                 */
/*     The Rector and Visitors of the University of Virginia            */
/*                                                                      */
/* This code may not be distributed further without permission          */
/*      from the University of Virginia.                                */
/* This code is distributed WITHOUT ANY WARRANTY.  No claims are        */
/*      made as to whether it serves any particular purpose or even     */
/*      works at all.                                                   */
/*                                                                      */
/************************************************************************/

#include <stdio.h>
#include <ctype.h>
#include "types.h"
#include "stopset.h"
#include "size.h"
#include "tword.h"
#include "ident.h"
#include "scan.h"
#include "object.h"
#include "required.h"
#include "../rt/runtime.h"

extern int opt_s;

STOPBUF
	add_op,
	block_begin,
	boole_op,
	char_op,
	const_begin,
	expr_begin,
	factor_begin,
	int_op,
	mul_op,
	nolabel,
	point_op,
	real_op,
	rel_op,
	select_begin,
	set_op,
	stmt_begin,
	term_begin,
	type_begin
;

OBJECT
	*std_boolean,
	*std_char,
	*std_error,
	*std_external,
	*std_forward,
	*std_input = OB_NULL,
	*std_integer,
	*std_nil,
	*std_output= OB_NULL,
	*std_real,
	*std_string,
	*std_text,
	*std_universal
;

/* id_init puts pascal reserved words into the name table */

id_init()
{
	struct kw {
		char *keyword;
		int symbol;
	};

	static struct kw keywtab[] = {
		"and",		SY_AND,
		"array",	SY_ARRAY,
		"begin",	SY_BEGIN,
		"case",		SY_CASE,
		"const",	SY_CONST,
		"div",		SY_DIV,
		"do",		SY_DO,
		"downto",	SY_DOWNTO,
		"else",		SY_ELSE,
		"end",		SY_END,
		"file",		SY_FILE,
		"for",		SY_FOR,
		"function",	SY_FUNC,
		"goto",		SY_GOTO,
		"if",		SY_IF,
		"in",		SY_IN,
		"label",	SY_LABEL,
		"mod",		SY_MOD,
		"nil",		SY_NIL,
		"not",		SY_NOT,
		"of",		SY_OF,
		"or",		SY_OR,
		"otherwise",	SY_OTHERW,
		"packed",	SY_PACKED,
		"procedure",	SY_PROC,
		"program",	SY_PROGRAM,
		"record",	SY_RECORD,
		"repeat",	SY_REPEAT,
		"set",		SY_SET,
		"then",		SY_THEN,
		"to",		SY_TO,
		"type",		SY_TYPE,
		"until",	SY_UNTIL,
		"var",		SY_VAR,
		"while",	SY_WHILE,
		"with",		SY_WITH,
		"",			SY_ENDFILE
	};
	register struct kw *k;

	/* if -s option used, "otherwise" is an identifer. */

	if (opt_s)
		(void) id_get("otherwise", SY_IDENT);
	for (k = keywtab; k->symbol != SY_ENDFILE; k++)
		(void) id_get(k->keyword, k->symbol);
}

/*
 * ob_init defines an object and fills in its type word and size
 */

OBJECT *
ob_init(name, kind, flags, tword, size)
	char *name;
	int kind, flags, size;
	TWORD tword;
{
	register OBJECT *p;
	IDENT *id;

	id = name ? id_get(name, SY_IDENT) : ID_NULL;
	p = ob_define(id, kind, flags);
	p->ob_tword = tword;
	p->ob_size = size;
	return(p);
}

/*
 * ob_req_subp defines a required function or procedure
 */

ob_req_subp(name, kind, funcid, type)
	char *name;
	int funcid, kind;
	OBJECT *type;
{
	register OBJECT *func;
	TWORD tword;
	tword = type ? type->ob_tword : TW_UNDEF;
	func = ob_init(name, kind, 0, TW_INCREF(tword) - TW_PTR + TW_FTN, 0);
	func->ob_type = type;
	func->ob.subp.standard = funcid;
	func->ob.subp.parameter = OB_NULL;
}


/*
 * p_init does all of the initialization for the parser including
 * definition of standard types and constants, required functions and
 * procedures, parsing symbol sets.
 */

p_init()
{
	OBJECT *p;

	/* treat underscore like a lower case letter (see <ctype.h>) */

	if (!opt_s)
		(_ctype + 1)['_'] |= _L;

	/* initialize reserved words */

	id_init();

	/* standard types */

	std_boolean = ob_init("boolean", OB_STDTYPE, 0, TW_INT, SZ_INT);
	std_boolean->ob.subrange.min = 0;
	std_boolean->ob.subrange.max = 1;

	std_char = ob_init("char", OB_STDTYPE, 0, TW_CHAR, SZ_CHAR); 
	std_char->ob.subrange.min = 0;
	std_char->ob.subrange.max = SZ_MAXCHAR;

	std_integer = ob_init("integer", OB_STDTYPE, 0, TW_INT, SZ_INT);
	std_integer->ob.subrange.min = -SZ_MAXINT;
	std_integer->ob.subrange.max =  SZ_MAXINT;

	std_real = ob_init("real", OB_STDTYPE, 0, TW_DOUBLE, SZ_DOUBLE);

	std_text = ob_init("text", OB_FILE, 0, TW_STRTY,
		ALIGN(sizeof(FILEAREA) + SZ_CHAR, AL_ANY));
	std_text->ob_type = std_char;

	/* universal type (used for error handling, etc.) */

	std_universal = ob_init((char*)0, OB_STDTYPE, 0, TW_INT, SZ_INT);
	std_universal->ob.subrange.min = std_universal->ob.subrange.max = 0;
	std_universal->ob_type = std_universal;

	/* standard constants */

	p = ob_init("false", OB_CONST, 0, TW_INT, SZ_INT);
	p->ob_type = std_boolean;
	p->ob.const.val.i = 0;

	p = ob_init("true", OB_CONST, 0, TW_INT, SZ_INT);
	p->ob_type = std_boolean;
	p->ob.const.val.i = 1;

	p = ob_init("maxint", OB_CONST, 0, TW_INT, SZ_INT);
	p->ob_type = std_integer;
	p->ob.const.val.i = SZ_MAXINT;

	std_nil = ob_init((char*)0, OB_POINTER, 0, TW_PTR, SZ_PTR);
	std_nil->ob_type = std_universal;

	/* template type used for string constants */

	std_string = ob_init((char*)0, OB_ARRAY, OB_PACKED,
		TW_INCREF(TW_ARY + TW_CHAR), 0);
	std_string->ob_type = std_char;
	p = ob_init((char*)0, OB_SUBRANGE, 0, TW_INT, SZ_INT);
	p->ob_type = std_integer;
	std_string->ob.array.indextype = p;
	std_string->ob.array.lower = 1;

	/* directives */

	std_forward = ob_define(id_get("forward", SY_IDENT), OB_DIRECTIVE, 0);
	std_external = ob_define(id_get("external", SY_IDENT), OB_DIRECTIVE, 0);

	/* required functions and procedures */

	ob_req_subp("abs", OB_FUNC, FUNC_ABS, OB_NULL);
	ob_req_subp("arctan", OB_FUNC, FUNC_ARCTAN, std_real);
	ob_req_subp("argc", OB_FUNC, FUNC_ARGC, std_integer);
	ob_req_subp("argv", OB_PROC, PROC_ARGV, OB_NULL);
	ob_req_subp("chr", OB_FUNC, FUNC_CHR, std_char);
	ob_req_subp("clock", OB_FUNC, FUNC_CLOCK, std_integer);
	ob_req_subp("cos", OB_FUNC, FUNC_COS, std_real);
	ob_req_subp("date", OB_PROC, PROC_DATE, OB_NULL);
	ob_req_subp("dispose", OB_PROC, PROC_DISPOSE, OB_NULL);
	ob_req_subp("eof", OB_FUNC, FUNC_EOF, std_boolean);
	ob_req_subp("eoln", OB_FUNC, FUNC_EOLN, std_boolean);
	ob_req_subp("exp", OB_FUNC, FUNC_EXP, std_real);
	ob_req_subp("get", OB_PROC, PROC_GET, OB_NULL);
	ob_req_subp("ln", OB_FUNC, FUNC_LN, std_real);
	ob_req_subp("new", OB_PROC, PROC_NEW, OB_NULL);
	ob_req_subp("odd", OB_FUNC, FUNC_ODD, std_boolean);
	ob_req_subp("ord", OB_FUNC, FUNC_ORD, std_integer);
	ob_req_subp("pack", OB_PROC, PROC_PACK, OB_NULL);
	ob_req_subp("page", OB_PROC, PROC_PAGE, OB_NULL);
	ob_req_subp("pred", OB_FUNC, FUNC_PRED, OB_NULL);
	ob_req_subp("put", OB_PROC, PROC_PUT, OB_NULL);
	ob_req_subp("random", OB_FUNC, FUNC_RANDOM, std_real);
	ob_req_subp("read", OB_PROC, PROC_READ, OB_NULL);
	ob_req_subp("readln", OB_PROC, PROC_READLN, OB_NULL);
	ob_req_subp("reset", OB_PROC, PROC_RESET, OB_NULL);
	ob_req_subp("rewrite", OB_PROC, PROC_REWRITE, OB_NULL);
	ob_req_subp("round", OB_FUNC, FUNC_ROUND, std_integer);
	ob_req_subp("seed", OB_PROC, PROC_SEED, OB_NULL);
	ob_req_subp("sin", OB_FUNC, FUNC_SIN, std_real);
	ob_req_subp("sqr", OB_FUNC, FUNC_SQR, OB_NULL);
	ob_req_subp("sqrt", OB_FUNC, FUNC_SQRT, std_real);
	ob_req_subp("succ", OB_FUNC, FUNC_SUCC, OB_NULL);
	ob_req_subp("sysclock", OB_FUNC, FUNC_SYSCLOCK, std_integer);
	ob_req_subp("trunc", OB_FUNC, FUNC_TRUNC, std_integer);
	ob_req_subp("unpack", OB_PROC, PROC_UNPACK, OB_NULL);
	ob_req_subp("wallclock", OB_FUNC, FUNC_WALLCLOCK, std_integer);
	ob_req_subp("write", OB_PROC, PROC_WRITE, OB_NULL);
	ob_req_subp("writeln", OB_PROC, PROC_WRITELN, OB_NULL);

	/* initialize sets needed by the parser */

	set_or(block_begin, set_cons(SY_BEGIN, SY_CONST, SY_FUNC,
		SY_LABEL, SY_PROC, SY_TYPE, SY_VAR, 0), S0);

	set_or(const_begin, set_cons(SY_PLUS, SY_MINUS, SY_STRING,
		SY_DIGSEQ, SY_IDENT, SY_REAL, 0), S0);

	set_or(factor_begin, set_cons(SY_LPAREN, SY_LBRAC, SY_NIL, SY_NOT,
		SY_STRING, SY_DIGSEQ, SY_IDENT, SY_REAL, 0), S0);

	set_or(term_begin, factor_begin, S0);

	set_or(expr_begin, term_begin, set_cons(SY_PLUS, SY_MINUS, 0), S0);

	set_or(type_begin, const_begin, set_cons(SY_LPAREN, SY_UPARROW,
		SY_ARRAY, SY_FILE, SY_PACKED, SY_RECORD, SY_SET, 0), S0);

	set_or(nolabel, set_cons(SY_DIGSEQ, SY_IDENT, SY_BEGIN, SY_CASE,
		SY_FOR, SY_GOTO, SY_IF, SY_REPEAT, SY_WHILE, SY_WITH, 0), S0);
	
	set_or(stmt_begin, nolabel, set_cons(SY_DIGSEQ, 0), S0);

	set_or(select_begin, set_cons(SY_LBRAC, SY_DOT, SY_UPARROW, 0), S0);

	set_or(rel_op, set_cons(SY_LT, SY_LE, SY_EQUAL, SY_NE, SY_GE,
		SY_GT, SY_IN, 0), S0);

	set_or(add_op, set_cons(SY_PLUS, SY_MINUS, SY_OR, 0), S0);

	set_or(mul_op, set_cons(SY_STAR, SY_SLASH, SY_AND, SY_DIV,
		SY_MOD, 0), S0);

	set_or(char_op, set_cons(SY_LT, SY_LE, SY_EQUAL, SY_NE,
		SY_GE, SY_GT, 0), S0);

	set_or(real_op, char_op, set_cons(SY_PLUS, SY_MINUS, SY_STAR,
		SY_SLASH, 0), S0);

	set_or(int_op, real_op, set_cons(SY_DIV, SY_MOD, 0), S0);

	set_or(set_op, set_cons(SY_PLUS, SY_MINUS, SY_STAR, SY_EQUAL, SY_NE,
		SY_GE, SY_LE, 0), S0);

	set_or(point_op, set_cons(SY_EQUAL, SY_NE, 0), S0);

	set_or(boole_op, char_op, set_cons(SY_NOT, SY_AND, SY_OR, 0), S0);

	/* initialize parse tree storage */

	nd_init();
	c_init();
}
