ftp.nice.ch/pub/next/developer/languages/ada/Adaed.1.11.s.tar.gz#/Adaed-1.11.0a/adaprs.c

This is adaprs.c in view mode; [Download] [Up]

/*
 * Copyright (C) 1985-1992  New York University
 * 
 * This file is part of the Ada/Ed-C system.  See the Ada/Ed README file for
 * warranty (none) and distribution info and also the GNU General Public
 * License for more details.

 */
/*			
 *						Parser for ADA
 *			
 *						Written by
 *						Nathan Glasser 
 *						Brian Siritzky
 *
 *
 * This program is invoked with command line arguments to specify the
 * Ada source file and options. The LALR(1) parser consists of a parser driver
 * which uses tables produced by a parser generator. The information in the
 * tables is used to initialize program arrays statically. Two stacks are
 * kept as the parser performs shifts and reductions: state_stack, the state
 * stack, and prs_stack, the stack of grammar symbols (tokens and non-terminals)
 * and their developing abstract syntax trees. The two stacks are seperate, and
 * reductions are deferred until the next shift to allow for the inclusion of
 * an error recovery routine which needs to examine the symbols which 
 * participated in the last reduction. Reductions are done by calling the
 * reduce() function, which is generated by LALR from the file ada.g with
 * the grammar and reduce actions.
 *
 */

#include "ada.h"
#include "ifile.h"
#include "miscprots.h"
#include "libfprots.h"
#include "actionprots.h"
#include "adaredprots.h"
#include "prsutilprots.h"
#include "prserrprots.h"
#include "adalexprots.h"
#include "adaprsprots.h"

static void prsinit();
static void lrparse();
static void errorinit(struct two_pool **, struct two_pool **, int *);

/* Global variables */

struct prsstack *prs_stack = NULL,	/* Stack containing symbols */
*curtok,		/* Current input token */
*PREVTOK = NULL;	/* Previous input token */
struct two_pool *sta_stack;		/* The state stack */
char *strjoin();
FILE *MALFILE;				/* smalloc measurement file */
/* not used by parser */
FILE *efopen();
FILE *efopenl();
IFILE *ifopen();
IFILE *astfile;				/* File pointer for ast file */
FILE  *adafile,				/* File pointer for ada source file */
*msgfile,				/* File pointer for msgs file */
*errfile;				/* File pointer for error & debug info*/

struct ast *opt_node, *any_node;	/* Special nodes to indicate
					   optional elements in the ada
					   syntax, or a node to be filled in */
int redopt = 0;				/* Flag for printing rules */
int astopt = 1;				/* Flag for printing ast */
int erropt = 0;				/* Flag for printing debugging info */
int termopt = 0;			/* Flag for terminal display */
int debugopt = 0;			/* True if any debugging options on */
int trcopt = 0;				/* True if erropt or redopt set */
extern int optind;			/* global option index */

int n_sta_stack;		    /* The size of the state stack */
int n_prs;
struct prsstack **tokens = NULL;    /* Token stack */
int tokind = -1;
int toksiz = 1;	    /* Size of array used for token stack */
int tokbottom = 0;

int err_ct = 0;

extern int optind;
extern char *optarg;

int main(int argc, char **argv)				/*;main*/
{
	/* Variables for reading command line and figuring out names
       of files, etc. */
	char *adafilename = NULL;
	char *sourcefilename;
	char *basefilename = NULL;
	char *errfilename = NULL;
	char *lib_name;
	char *t_name;
	int  c, n, i, w_trace = 1, r_trace = 0, iot_level = 2;
	int  lib_option = FALSE;
	int  new_library = FALSE;
	int iot_ast_w = 0; /* nonzero to trace ast tree write */
	int unbufflag = 0;
	int  prefix_len, base_len, suffix_len;
	char *basep;

	/* The parser bombs on VAX if no arguments, so for now fail and
     * also modify usage message to indicate that filename required
     */

	/* Figure out what the command line means */
	while ((c = getopt(argc, argv, "f:l:np:")) != EOF)
	{
		switch (c) {
		case 'l': /* using existing library */
			lib_option = TRUE;
			lib_name = emalloc(strlen(optarg) + 1);
			strcpy(lib_name, optarg);
			break;
		case 'n': /* indicates new library */
			new_library = TRUE;
			lib_option = TRUE;
			break;
		case 'f' :
			n = strlen(optarg);
			for (i = 0; i < n; i++) {
				switch (optarg[i]) {

				case 'n': 
					iot_set_opt_number(0);
					break;
				case 'p': 
					if (w_trace) iot_ast_w = iot_level;
					break;
				case 'd': 
					iot_set_opt_desc(0); 
					break;
				case 'r': 
					w_trace= FALSE; 
					r_trace= TRUE; 
					break;
				case 'w': 
					r_trace = FALSE; 
					w_trace = TRUE; 
					break;
				case '1': 
					iot_level = 1; 
					break;
				case '2': 
					iot_level = 2; 
					break;
				}
			}
			break;
		case 'p': /* parser sub options */
			n = strlen(optarg);
			for (i = 0; i < n; i++) {
				switch (optarg[i]) {
				case 'a' :
					astopt = 0;
					break;
				case 'b' :  /* unbuffer output */
					unbufflag = 1;
					break;
				case 'e' :
					erropt = 1 ;
					break ;
				case 'r' : /* display of reductions + source */
					redopt = 1;
					break;
					/* terminal display of source + error messages */
				case 't':
					termopt = 1;
					break;
				}
			}
			break;
		default:
			exitp(RC_ABORT);
		}
	}
	if (optind < argc) {
		adafilename = argv[optind];
		basep = parsefile(adafilename, &prefix_len, &base_len, &suffix_len);
		basefilename = emalloc(base_len + 1);
		strncpy(basefilename, basep, base_len);
		if (suffix_len == 0) { /* if suffix .ada implied */
			sourcefilename = emalloc(strlen(adafilename) + 4 + 1);
			strcpy(sourcefilename, adafilename);
			strcat(sourcefilename, ".ada");
		}
		else {
			sourcefilename = adafilename;
		}
		adafile = efopen(sourcefilename, "r", "t");
	}
	else {
		fprintf(stderr, "Bad usage: no adafile specified.\n");
		exitp(RC_ABORT);
	}
	t_name = libset(lib_name);
	trcopt = redopt || erropt ;
	debugopt = termopt || redopt || erropt ;
	if (astopt)
		astfile = ifopen(basefilename, "ast", "w", "p", iot_ast_w, 0);
	msgfile = efopenl(basefilename, "msg", "w", "t");
	if (trcopt) {
#ifndef IBM_PC
		errfile = efopenl(basefilename, "err", "w", "t");
#else
		/* write to stdout on PC */
		errfile = stdout;
#endif
	}
	else {
		errfilename = NULLFILENAME ;
		errfile = (FILE *)0;
	}

	if (unbufflag)
	{
		if (astopt)
			setbuf(astfile->fh_file, (char *)0);
		if (trcopt)
			setbuf(errfile, (char *)0);
		setbuf(msgfile, (char *)0);
	}

	prsinit();

	lrparse();
	if (debugopt && err_ct)
		printf("%d parse error(s) found.\n", err_ct);

	fclose(adafile);
	if (astopt) {
		putnum(astfile, "end-file", -1); /* to indicate end of file */
		ifclose(astfile);
	}
	fclose(msgfile);
	if (trcopt)
		fclose(errfile);
	exitp(err_ct > 0 ? RC_ERRORS : RC_SUCCESS);
}

static void prsinit()					/*;prsinit*/
{
	opt_node = new_node(AS_OPT);
	any_node = new_node(AS_OPT);
}

/* 
 *			Lrparse: Parser driver. 
 * Gettok() is called to return the next token.
 *  Action is called to compute the next action to be taken given the
 *  state and current token. If the action is a reduction, the reduction
 *  of the state stack is performed, the reduction of the parse stack
 *  is deferred until the next shift by putting onto the queue marked by
 *  topred and lastred, and the new state is computed with another call to
 *  action acting as a GOTO. If the action is a shift, all deferred reductions
 *  are performed, the current token is added to the parse stack, and
 *  the new state is equal to the value returned by action(). When the action
 *  is shift and is equal to NUM_STATES, this is an accept action, and we 
 *  return. 
 */

/* 
 *	A stack of tokens is kept so as to conform with the addition of an 
 *  error recovery routine. Tokens is the variable which is used as an
 *  array to store the tokens. Tokind is the index into this array indicating
 *  the next token to be returned, or -1 if there are no stored tokens.
 *  The macro NEXTTOK is designed for use with this scheme. Toksiz represents
 *  the size of the array being used for the token stack at any given time.
 *  If we need more space, we call realloc() to give us more storage, and
 *  change toksiz to reflect this change. 
 */

/*
  *	Changes made for error recovery		(12/28/83-NG)
  *
  *  Before the call to prserr(), some manipulation of the state and
  *  parse stacks must be performed. A "common point" between these
  *  two stacks must be kept. Before the call to prserr(), the state
  *  stack from the common point must be freed, and then increased to a 
  *  size equal that of the parse stack. This is done by computing
  *  states from the current top of the state stack and the corresponding
  *  position in the parse stack, putting the new state on top and then
  *  using it to compute the next state in the same manner.
  *  This common point is implemented as follows :
  *  The variable sta_com_pt is a pointer to the element of the state
  *  stack which corresponds to the common point. The variable 
  *  prs_com_pt_ct is an integer telling how many elements, from the top
  *  of the parse stack, are needed to reach that element of the parse
  *  stack corresponding to the element in the state stack pointed to
  *  by sta_com_pt (in terms of the sizes of the stacks below these
  *  elements). After performing a shift, sta_com_pt is NULL, and 
  *  prs_com_pt_ct is 0. This is because all deferred reductions will
  *  have been performed, putting the two stacks in alignment. The NULL
  *  indicates that the common point is above (the top of) the state
  *  stack. When there is a reduction, the sta_com_pt may shift down in
  *  the stack or remain the same. If it shifts downwards, then
  *  prs_com_pt_ct is shifted also by the number of elements sta_com_pt
  *  was shifted. (When this first happens sta_com_pt becomes non-NULL)
  *	 Just before the call to prserr(), first free the elements of the 
  *  state stack using the pointer we have to the last element we wish
  *  freed. Then copy prs_com_pt_ct elements from the top of the parse
  *  stack into an array. We then compute the states from the state on top
  *  of the state stack and the next element of the parse stack (from the 
  *  array).
  *
  */



static void lrparse()				/*;lrparse*/
{
	struct two_pool *topred = NULL,	/* Top of reduction queue */
	*lastred = NULL;	/* Bottom of reduction queue */
	int act;				/* Pending action */
	struct two_pool *tmp, *top;		/* Temps */
	int n,		/* Number of symbols being reduced */
	red;		/* Reduction to be performed */
	struct two_pool *sta_com_pt = NULL; /* Common point stuff */
	int i;
	int prs_com_pt_ct = 0;
	int prs_ct_flag;

	sta_stack = TALLOC();
	sta_stack->val.state = 1;
	sta_stack->link = NULL;
	curtok = NEXTTOK;

	while (1)			/* Main parse loop */
	{
		/*	Determine action */

#ifdef DEBUG1
		if (trcopt) {
			fprintf(errfile, "action(%d, %d) = ", sta_stack->val.state, curtok->symbol);
		}
#endif
		act = action(sta_stack->val.state, curtok->symbol);
#ifdef DEBUG1
		if (trcopt)
			fprintf(errfile, "%d \n", act) ;
#endif

		if (!act)		/* ERROR */
		{
			if (topred != NULL)
				errorinit(&sta_stack, &sta_com_pt, &prs_com_pt_ct) ;

			prserr(curtok);		/* THIS IS IT : PRSERR */

			curtok = NEXTTOK ;

#ifdef DEBUG
			/* print debugging information */
			if (trcopt) {
				fprintf(errfile, "RECOVERED\n");
				fprintf(errfile, "STATE STACK:\n");
				dump_stack(sta_stack);
				fprintf(errfile, "PARSE STACK:\n");
				dump_prsstack(prs_stack);
				fprintf(errfile, "NEXT TOKEN: %s\n", TOKSTR(curtok->symbol));
			}
#endif

			/* 
			 * Free any pending reductions 
			 */
			if (topred != NULL) {
				TFREE(topred, lastred) ;
				topred = lastred = NULL ;
			}
		}

		else if (act <= NUM_STATES) /* Shift */
		{
			/* Perform deferred reductions on prs_stack */

			if (topred != NULL) {

				tmp = topred;
				while (topred != NULL) {
					reduce((int)topred->val.reduction);
					topred = topred->link;
				}
				TFREE(tmp, lastred);
				lastred = NULL;
			}
			tmp = TALLOC();
			tmp->val.state = act;
			tmp->link = sta_stack;
			sta_stack = tmp ;
			n_sta_stack ++ ;
			curtok->prev = prs_stack;
			prs_stack = curtok;
			PREVTOK = copytoken(curtok) ;
			curtok = NEXTTOK;
			n_prs ++ ; /* Increment the size of the parse stack */

			sta_com_pt = NULL;		/* Initialize comm pt stuff */
			prs_com_pt_ct = 0;

			if (act == NUM_STATES)	/* Accept */
				return;
		}
		else /* Reduce */
		{
			red = act - NUM_STATES - 1;
			n = rhslen[red];
			tmp = TALLOC();
			tmp->val.reduction = red;
			tmp->link = NULL;
			prs_ct_flag = 0;
			if (lastred == NULL)
				topred = lastred = tmp;
			else {
				lastred->link = tmp;
				lastred = tmp;
			}
			if (!n) {
				tmp = TALLOC();
				tmp->link = sta_stack;
				sta_stack = tmp;
			}
			else if (n > 1) {
				top = sta_stack;
				n_sta_stack = n_sta_stack - n + 1 ;
				for (i = n - 2; i--; ) {
					if (sta_com_pt == sta_stack)   /* The common point */
					{				   /* might be freed here */
						sta_com_pt = NULL;
						prs_ct_flag = 1;
						prs_com_pt_ct += 2;
					}
					else if (prs_ct_flag)    /* Keep count of no. of places */
						prs_com_pt_ct++;	/* common point will move */
					sta_stack = sta_stack->link;
				}
				if (sta_com_pt == sta_stack) {
					sta_com_pt = NULL;
					prs_com_pt_ct ++ ;
				}
				tmp = sta_stack;
				sta_stack = sta_stack->link;
				TFREE(top, tmp);
			}

			/* Set sta_com_pt if needed, and set prs_com_pt_ct to
	       point to right part of prs_stack in the case in which 
	       this is the first reduction after a shift. */
			if (sta_com_pt == NULL) {
				sta_com_pt = sta_stack;
				if (!prs_com_pt_ct)
					prs_com_pt_ct = n ;
			}

			sta_stack->val.state = 
			    action((int)sta_stack->link->val.state, lhs[red]);
		}
	}
}

static void errorinit(struct two_pool **psta_stack,
  struct two_pool **psta_com_pt, int *pprs_com_pt_ct)	/*;errorinit*/
{
	struct two_pool *tmp;
	struct prsstack **tmp_prs_array;
	struct prsstack *prs_temp;
	int i;

	if (*psta_com_pt == NULL)
		return;
	tmp = (*psta_com_pt)->link;
	TFREE(*psta_stack, *psta_com_pt);
	*psta_stack = tmp;
	*psta_com_pt = NULL;
	if (!*pprs_com_pt_ct)
		return;
	tmp_prs_array = (struct prsstack **)malloc((unsigned)(*pprs_com_pt_ct * 
	  (sizeof(struct prsstack *))));
	for (i = 0, prs_temp = prs_stack; i < *pprs_com_pt_ct; i++,
	  prs_temp = prs_temp->prev)
		tmp_prs_array[i] = prs_temp;
	for (i = *pprs_com_pt_ct - 1; i >= 0; i--) {
		tmp = TALLOC();
		tmp->link = *psta_stack;
		tmp->val.state = action((int)(*psta_stack)->val.state,
		  tmp_prs_array[i]->symbol);
		*psta_stack = tmp;
	}
	free((char *)tmp_prs_array);
	*pprs_com_pt_ct = 0;
}

struct prsstack *tokfromlist()			/*;tokfromlist*/
{
	int tmp = tokind;

	tokind = (tokind - 1 + toksiz) % toksiz;
	return(tokens[tmp]);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.