[alt.sources] PL/M to C converter Part 01/03

bob@reed.UUCP (Bob Ankeney) (04/10/91)

#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
# This is part 1 of a multipart archive                                    
# do not concatenate these parts, unpack them in order with /bin/sh        
#
#	Run the following text with /bin/sh to create:
#	  README
#	  CAVEATS.DOC
#	  FILES
#	  at_decl.cvt
#	  const.c
#	  context.c
#	  control.c
#	  convert.c
#	  cvt.h
#	  cvt_id.h
#	  decl_out.c
#	  declare.c
#	  defs.h
#	  error.c
#	  io.c
#	  lit.c
#	  main.c
#	  makefile
#	  makefile.ibm
#	  mem.c
#	  misc.h
#	  parse.c
#	  struct.h
#	  test.c.out
#	  test.plm
#	  tkn_defs.h
#	  tkn_ext.h
#	  token.c
#	  tokens.h
#	  typedefs.c
#	  version.c
#
if test -r s2_seq_.tmp
then echo "Must unpack archives in sequence!"
     next=`cat s2_seq_.tmp`; echo "Please unpack part $next next"
     exit 1; fi
sed 's/^X//' << 'SHAR_EOF' > README &&
X     This is a PL/M to C converter.  It will take most PL/M code and do a nice
Xjob of converting it to C.  It tries to be intelligent about leaving formatting
Xand comments intact.  This version supports PL/M-286.  It is something I wrote
Xabout a year ago to convert several meg of source code, and it did a 99.5%
Xconversion.  I was later handed some source code that it crashed on, and I
Xextended it to support that code too.
X     Please keep in mind that this may well not work for your code.  It has
Xbeen tested only on a few sets of code, each following its own set of coding
Xstandards.  Also, don't expect a lot of support from me, as my interest in
XPL/M is next to none.  I no longer work for the employer for whom I wrote
Xthis converter, but they have given me permission to own and post the sources.
XI will, time permitting, collect bug fixes and post patches to the software.
XPlease mail fixes directly to me, as I may miss any posting of them.  If
Xanyone is interested in taking over maintenance of this code, please let me
Xknow!
X     The source code compiles under Unix.  I've compiled it on a Sun-4, a VAX
Xrunning Ultrix, and a VAX running Mt. Xinu.  At one time I had a version that
Xran under MSDOS, but I can't guarantee it will now.  I've included a makefile
Xfor use with Turbo-C.  You need to define IBMPC to compile it.  What it could
Xreally use is tuning for a large memory model, as in it's present state, it
Xcan only handle small source files.  It could also benefit from a good man
Xpage.
X     The converter expects source code to be in "proper" format (i.e. proper
Xuse of EXTERNAL declarations, and following of the Intel PL/M grammar as the
Xconverter knows it.)  It has some moderate error-recovery, but may well dump
Xcore if it expects one thing and gets another.
X     I've included a garbage file test.plm; typeing "plm2c test.plm" should
Xresult in a test.c file that is identical to the provided test.c.out.
X     See the file CAVEATS.DOC for compatibility issues.
X
X     Hope you find it useful!
X
X     Robert Ankeney
X     April 9, 1991
X     ...!tektronix!bob@reed.bitnet
X
X
SHAR_EOF
chmod 0644 README || echo "restore of README fails"
sed 's/^X//' << 'SHAR_EOF' > CAVEATS.DOC &&
XSome notes about the PL/M to C converter:
X
XWith case conversion enabled by the "ifdef" in main.c, all upper case 
Xcharacters in an identifier are converted to lower case, and all lower case 
Xcharacters are converted to upper case except for identifiers declared 
XLITERALLY, in which case the identifier is not case converted.
X
XDollar signs used in identifiers are discarded.
X
XThe use of the AND, OR and NOT operators are converted to &&, ||, and !
Xoperators respectively.  This should work, but conversion to &, |, and ~
Xmay be desirable in many cases.  There is no clear way to distinguish which
Xconversion to use, thus the previous conversions were chosen.  A #define
Xin tokens.h allows either convention to be chosen.  A more intelligent
Xexpression parser could do a better job of determining use of these operators.
X
XLabels are limited in scope to that defined in C.  That is, use of labels is
Xlimited to the current function.  PL/M allows external labels.
X
XThe dot operator is treated the same as the @ operator (converted to a &
Xreference).
X
XConstant lists of the form:
X     @('string', 0)
Xare converted to:
X     "string"
X
XConstant lists of the form:
X     @('string')
Xare converted to:
X     's', 't', 'r', 'i', 'n', 'g'
X
XBYTE strings of the form:
X     'string'
Xare converted to:
X     's', 't', 'r', 'i', 'n', 'g'
X
XADDRESSes and SELECTORs are not supported.
X
XVariables declared AT in one module and EXTERNAL in another will produce
Xincorrect results, as the EXTERNAL declared variable will not be treated
Xas a pointer.  For example, in module A:
X
X     PL/M code:                           C code:
X     ---------------------------------    ----------------------------------
X     DECLARE MEMVAR BYTE AT(8000H);       BYTE *memvar = (BYTE *) 0x8000;
X     MEMVAR = 14H;                        (*memvar) = 0x14;
X
XAnd in module B:
X
X     PL/M code:                           C code:
X     ---------------------------------    ----------------------------------
X     DECLARE MEMVAR BYTE EXTERNAL;        BYTE memvar;
X     MEMVAR = 14H;                        memvar = 0x14;
X
XTo avoid this problem, list each AT variable used on a single line in a file
Xcalled "at_decl.cvt".
X
XVariable declarations within a procedure with the PUBLIC attribute *probably*
Xshould be placed prior to the procedure definition. Currently, the PUBLIC
Xattribute is ignored.
X
XVariable declarations of type POINTER are treated as type void.
XBASED variables are treated as a pointer to the based variable.
XFor example, for the following declarations, the associated C code is
Xgenerated:
X
X     PL/M code:                           C code:
X     ---------------------------------    ----------------------------------
X     DECLARE I BYTE;                      BYTE i;
X     DECLARE ITEM_PTR POINTER;            void *item_ptr;
X     DECLARE ITEM BASED ITEM_PTR BYTE;    BYTE **item = (BYTE **) &item_ptr;
X     ITEM_PTR = @I;                       item_ptr = &i;
X     ITEM = 77H;                          (**item) = 0x77;
X
X
XCare should be taken in the use of LITERALLY declared variables.  Such
Xdeclarations are converted to a #define directive.  With the cvt.h flag
XPARSE_LITERALS defined, the converter attempts to parse the contents of
Xall LITERALLY declared variables as the definition for the #define
Xdirective.  With PARSE_LITERALS undefined, no parsing takes place.  Thus,
Xfor the declaration:
X	DECLARE MAX_COUNT LITERALLY '55H';
Xthe code generated with PARSE_LITERALS defined is:
X	#define MAX_COUNT 0x55
Xand the code generated with PARSE_LITERALS undefined is:
X	#define MAX_COUNT 55H
X
X
XControl directives within comments are ignored.
X
XThe procedure attribute REENTRANT is ignored.  Technically, all PL/M variables
Xare static and could be declared as such in all but REENTRANT procedures.
XThis was not done, as it was deemed improbable that any problems would result.
XThe user should keep this fact in mind though.  Especially in cases where the
XC compiler warns about using a variable before it has been defined.
X
XIn most cases, white space (spaces, tabs, returns, line-feeds and comments)
Xare retained in their appropriate place.  In obscure instances, white space
Xmay be discarded for the sake of simpler code.  For example, white space in
Xsome portions of a DECLARE statement is discarded, since the structure of
Xa DECLARE statement is drastically converted.
X
XArray subscripts and function calls appear to be ambiguous.  The converter
Xkeeps a symbol table of DECLARATIONS to try to correctly distinguish one from
Xthe other.
X
X
SHAR_EOF
chmod 0660 CAVEATS.DOC || echo "restore of CAVEATS.DOC fails"
sed 's/^X//' << 'SHAR_EOF' > FILES &&
XREADME
XCAVEATS.DOC
XFILES
Xat_decl.cvt
Xconst.c
Xcontext.c
Xcontrol.c
Xconvert.c
Xcvt.h
Xcvt_id.h
Xdecl_out.c
Xdeclare.c
Xdefs.h
Xerror.c
Xio.c
Xlit.c
Xmain.c
Xmakefile
Xmakefile.ibm
Xmem.c
Xmisc.h
Xparse.c
Xstruct.h
Xtest.c.out
Xtest.plm
Xtkn_defs.h
Xtkn_ext.h
Xtoken.c
Xtokens.h
Xtypedefs.c
Xversion.c
SHAR_EOF
chmod 0644 FILES || echo "restore of FILES fails"
sed 's/^X//' << 'SHAR_EOF' > at_decl.cvt &&
SHAR_EOF
chmod 0644 at_decl.cvt || echo "restore of at_decl.cvt fails"
sed 's/^X//' << 'SHAR_EOF' > const.c &&
X
X
Xfoop(i, j)
Xshort i, j;
X{
X}
X
Xfloat foo()
X{
X}
X
X	WORD bletch;
X	void *ptr;
X
X	farp("Hi\014\037\253\036");
X	farp(&foo, &bar, &bletch);
X	bletch = foo + foop(1, 2);
X	bletch = foo + foop;
X	ptr = (void *)  &foo;
X	ptr = (void *)  &bar;
X	ptr = (void *)  &bletch;
X	foo();
X	bar();
X	(*ptr)();
X	(*bletch)();
X	(*ptr)(1, 2);
X
SHAR_EOF
chmod 0660 const.c || echo "restore of const.c fails"
sed 's/^X//' << 'SHAR_EOF' > context.c &&
X#include "misc.h"
X#include "defs.h"
X#include "cvt.h"
X#include "struct.h"
X
X/*
X *	Pointer to the current context
X */
XCONTEXT		*context_head;
X/*
X *	Pointer to all popped contexts
X */
XCONTEXT		*old_context;
X
X/*
X *	Search DECL_MEMBER list for symbol and if found, return TRUE
X *	and pointer to DECL_ID for that symbol.
X */
Xfind_member_symbol(symbol, decl_ptr, decl_id)
XTOKEN		*symbol;
XDECL_MEMBER	*decl_ptr;
XDECL_ID		**decl_id;
X{
X	DECL_ID	*var_ptr;
X
X	for (var_ptr = decl_ptr->name_list; var_ptr;
X			var_ptr = var_ptr->next_var) {
X		if (!strcmp(var_ptr->name->token_name, symbol->token_name)) {
X			*decl_id = var_ptr;
X			return TRUE;
X		}
X	}
X	*decl_id = NULL;
X	return FALSE;
X}
X
X/*
X *	Search DECL_MEMBER list for symbol.
X *	If found, return pointer to DECL_MEMBER containing that symbol
X *	in decl_found, and return TRUE.
X *	If not found, return null pointer in decl_found, and return FALSE.
X */
Xfind_list_symbol(symbol, decl_ptr, decl_found, decl_id)
XTOKEN		*symbol;
XDECL_MEMBER	*decl_ptr, **decl_found;
XDECL_ID		**decl_id;
X{
X	for (*decl_found = decl_ptr; *decl_found;
X			*decl_found = (*decl_found)->next_member) {
X		if (find_member_symbol(symbol, *decl_found, decl_id))
X			return TRUE;
X	}
X	return FALSE;
X}
X
X/*
X *	Search context for symbol.
X *	If found, return pointer to DECL_MEMBER containing that symbol
X *	in decl_found, return DECL_ID for that symbol in decl_id, and
X *	return TRUE.
X *	If not found, return null pointers in decl_found and decl_id,
X *	and return FALSE.
X */
Xfind_symbol(symbol, decl_found, decl_id)
XTOKEN		*symbol;
XDECL_MEMBER	**decl_found;
XDECL_ID		**decl_id;
X{
X	CONTEXT	*context_ptr;
X
X	for (context_ptr = context_head; context_ptr;
X			context_ptr = context_ptr->next_context) {
X		if (find_list_symbol(symbol, context_ptr->decl_head,
X				decl_found, decl_id))
X			return TRUE;
X	}
X	return FALSE;
X}
X
X/*
X *	Add a declaration to current context
X */
Xadd_to_context(decl)
XDECL_MEMBER	*decl;
X{
X	DECL_MEMBER	*decl_ptr;
X
X		/* Find end of declaration list */
X	for (decl_ptr = decl; decl_ptr->next_member; )
X		decl_ptr = decl_ptr->next_member;
X
X		/* Add current declarations to tail of new list */
X	decl_ptr->next_member = context_head->decl_head;
X	context_head->decl_head = decl;
X}
X
X/*
X *	Add a DECL list to context and NULL the list pointer
X */
Xadd_decl_to_context(decl)
XDECL	*decl;
X{
X	DECL	*decl_ptr;
X
X		/* Find end of declaration list */
X	for (decl_ptr = decl; decl_ptr; decl_ptr = decl_ptr->next_decl) {
X		if (decl_ptr->decl_list)
X			add_to_context(decl_ptr->decl_list);
X		decl_ptr->decl_list = NULL;
X	}
X}
X
X/*
X *	Push a new context of specified type and name
X */
Xnew_context(type, name)
Xint	type;
XTOKEN	*name;
X{
X	CONTEXT	*new_context;
X
X	get_context_ptr(&new_context);
X	new_context->context_type = type;
X	if (name) {
X		get_token_ptr(&new_context->context_name);
X		token_copy(name, new_context->context_name);
X	} else
X		new_context->context_name = NULL;
X	new_context->next_context = context_head;
X	context_head = new_context;
X}
X
X/*
X *	Pop current context and place on old context
X */
Xpop_context()
X{
X	CONTEXT	*popped_context;
X
X	popped_context = context_head;
X	context_head = popped_context->next_context;
X	popped_context->next_context = old_context;
X	old_context = popped_context;
X}
X
X/*
X *	Initializes context pointers
X */
Xinit_context()
X{
X	context_head = NULL;
X	old_context = NULL;
X}
X
SHAR_EOF
chmod 0660 context.c || echo "restore of context.c fails"
sed 's/^X//' << 'SHAR_EOF' > control.c &&
X#include "misc.h"
X#include "defs.h"
X#include "cvt.h"
X#include "struct.h"
X#include "tokens.h"
X#include "tkn_ext.h"
X
Xextern	char	*text_buffer;
Xextern	char	*text_ptr;
X
X/*
X *	Parse a control directive.
X *	Handles:		Abbreviation:
X *		$INCLUDE	$IC
X *		$SET
X *		$RESET
X *		$IF
X *		$ELSE
X *		$ELSEIF
X *		$ENDIF
X */
Xparse_control()
X{
X	TOKEN		ctl_token, token;
X	int		token_class;
X	RESERVED_WORD	*word_ptr;
X	char		include_file[128], *include_ptr;
X
X	token_class = get_token(&ctl_token);
X	if (token_class != IDENTIFIER) {
X		control_error("Invalid directive");
X		return;
X	}
X
X	for (word_ptr = &control_directives[0]; word_ptr->token != END_OF_FILE;
X			word_ptr++) {
X	    if ((strlen(word_ptr->name) == ctl_token.token_length) &&
X		!strncmp(word_ptr->name, ctl_token.token_start,
X				ctl_token.token_length)) {
X		switch (word_ptr->token) {
X
X		case C_INCLUDE :
X			token_class = get_token(&token);
X			if (token_class != LEFT_PAREN) {
X				control_error("'(' expected");
X				return;
X			}
X				/* Copy and send file name (up to ')') */
X			include_ptr = include_file;
X			while (*text_ptr != ')') {
X				if ((*text_ptr >= 'A') && (*text_ptr <= 'Z'))
X						/* Convert to lower case */
X					*include_ptr++ = *text_ptr++ + ' ';
X				else
X					*include_ptr++ = *text_ptr++;
X			}
X			*include_ptr++ = '\0';
X
X				/* Skip ')' */
X			text_ptr++;
X
X				/* Parse include file */
X			cvt_file(include_file);
X
X				/* Convert .plm to .c */
X			if (strcmp(include_ptr - 5, "plm")) {
X				(void) strcpy(include_ptr - 5, ".c");
X				include_ptr -= 2;
X			}
X
X			out_to_start();
X			out_str("#include");
X			out_must_white(&token);
X			out_char('"');
X			out_str(include_file);
X
X			out_char('"');
X			return;
X
X		default :
X			control_error("Non-supported directive");
X			return;
X		}
X	    }
X	}
X
X	control_error("Invalid directive");
X}
X
SHAR_EOF
chmod 0660 control.c || echo "restore of control.c fails"
sed 's/^X//' << 'SHAR_EOF' > convert.c &&
X#include <stdio.h>
X#ifdef IBMPC
X#include <stdlib.h>
X#endif
X#include "misc.h"
X#include "defs.h"
X#include "cvt.h"
X#include "struct.h"
X#include "tokens.h"
X
XBOOLEAN		syntax_error;
X
Xextern	char	*text_buffer, *text_ptr;
Xextern	int	line_count;
X
X/*
X *	Determine statement type and call appropriate parse routine.
X *	Return statement class or, if a reserved word, reserved word token.
X */
Xparse_statement(first_token)
XTOKEN	*first_token;
X{
X	int	token_type;
X
X		/* Flush standard output and standard error */
X	(void) fflush(stdout);
X	(void) fflush(stderr);
X
X		/* Flag no error yet */
X	syntax_error = FALSE;
X
X	switch (first_token->token_class) {
X
X	case RESERVED:
X		token_type = first_token->token_type;
X
X		switch (token_type) {
X
X		case DECLARE :
X			parse_declare(first_token);
X			break;
X
X		case DO :
X			parse_do(first_token);
X			break;
X
X		case IF :
X			parse_if(first_token);
X			break;
X
X		case THEN :
X			parse_then();
X			break;
X
X		case ELSE :
X			parse_else(first_token);
X			break;
X
X		case GOTO :
X			parse_goto(first_token);
X			break;
X
X		case GO :
X			parse_go(first_token);
X			break;
X
X		case CALL :
X			parse_call(first_token);
X			break;
X
X		case RETURN :
X			parse_return(first_token);
X			break;
X
X		case END :
X			parse_end(first_token);
X			break;
X
X		case DISABLE :
X			parse_int_ctl(first_token);
X			break;
X
X		case ENABLE :
X			parse_int_ctl(first_token);
X			break;
X
X		case OUTPUT :
X			parse_output(first_token);
X			break;
X
X		case OUTWORD :
X			parse_outword(first_token);
X			break;
X
X		case OUTHWORD :
X			parse_outhword(first_token);
X			break;
X
X		default :
X			parse_error("Illegal reserved word");
X			return ERROR;
X		}
X
X		return token_type;
X
X	case IDENTIFIER:
X		parse_identifier(first_token);
X		break;
X
X	case LABEL:
X		parse_label();
X		break;
X
X	case END_OF_LINE:
X		parse_eol(first_token);
X		break;
X
X	case END_OF_FILE:
X		out_white_space(first_token);
X		return END_OF_FILE;
X
X	default:
X		parse_error("Illegal statement");
X		return ERROR;
X
X	}
X
X	return first_token->token_class;
X}
X
Xparse_new_statement()
X{
X	TOKEN		first_token;
X
X		/* Get first token on line */
X	(void) get_token(&first_token);
X
X	return parse_statement(&first_token);
X}
X
Xparse_file()
X{
X	while (parse_new_statement() != END_OF_FILE) ;
X}
X
SHAR_EOF
chmod 0660 convert.c || echo "restore of convert.c fails"
sed 's/^X//' << 'SHAR_EOF' > cvt.h &&
X/*
X *	Parse LITERALLY declared strings
X */
X#define PARSE_LITERALS
X
X/*
X *	Ignore Invalid control errors
X */
X#define	IGNORE_CONTROL_ERRORS
X
X/*
X *	Convert lower case to upper and upper to lower in identifiers
X */
X#define	CONVERT_CASE
X
X/*
X *	If CONVERT_TYPES defined, use the following type conversions.
X */
X#define CONVERT_TYPES
X
X/*
X *	Type conversions
X */
X#define TYPE_BYTE	"BYTE"
X#define TYPE_WORD	"WORD"
X#define TYPE_DWORD	"DWORD"
X#define TYPE_INTEGER	"short"
X#define TYPE_REAL	"float"
X
X/*
X *	For initialized DATA, use this prefix.
X *	Probably should be "const" or "static".
X */
X#define TYPE_DATA	"const"
X
X/*
X *	Default POINTER type.
X */
X#define TYPE_POINTER	"void"
X
X/*
X *	Sizes of data types
X */
X#define SIZE_BYTE	1
X#define SIZE_WORD	2
X#define SIZE_DWORD	4
X
X/*
X *	Conversion operators
X */
X#define AND_OP	"&&"
X#define OR_OP	"||"
X#define NOT_OP	"!"
X/*
X#define AND_OP	"&"
X#define OR_OP	"|"
X#define NOT_OP	"~"
X*/
X/*
X#define AND_OP	"AND"
X#define OR_OP	"OR"
X#define NOT_OP	"NOT"
X*/
X
X/*
X *	Function call equivalent to OUTPUT(port) = expr
X *	Becomes: FUNC_OUTPUT(port, expr)
X */
X#define FUNC_OUTPUT	"outportb"
X
X/*
X *	Function call equivalent to OUTWORD(port) = expr
X *	Becomes: FUNC_OUTWORD(port, expr)
X */
X#define FUNC_OUTWORD	"outport"
X
X/*
X *	Function call equivalent to OUTHWORD(port) = expr
X *	Becomes: FUNC_OUTHWORD(port, expr)
X */
X#define FUNC_OUTHWORD	"outporth"
X
SHAR_EOF
chmod 0660 cvt.h || echo "restore of cvt.h fails"
sed 's/^X//' << 'SHAR_EOF' > cvt_id.h &&
X/*
X *	PL/M Cast function equivalents
X */
XCVT_ID cast_functions[] = {
X	"float",	TYPE_REAL,
X	"real",		TYPE_REAL,
X	"fix",		TYPE_INTEGER,
X	"int",		TYPE_INTEGER,
X	"signed",	TYPE_INTEGER,
X	"integer",	TYPE_INTEGER,
X	"unsign",	TYPE_WORD,
X	"word",		TYPE_WORD,
X	"byte",		TYPE_BYTE,
X	"dword",	TYPE_DWORD,
X	"pointer",	TYPE_POINTER,
X	"",		""
X};
X
X/*
X *	PL/M function equivalents
X */
XCVT_ID cvt_functions[] = {
X	"size",			"sizeof",
X	"abs",			"fabs",
X	"iabs",			"abs",
X	"input",		"inportb",
X	"inword",		"inport",
X	"setinterrupt",		"signal",
X	"initrealmathunit",	"_fpreset",
X	"",		""
X};
X
X/*
X *	PL/M identifier equivalents
X */
XCVT_ID cvt_identifiers[] = {
X	"getrealerror",		"_status87()",
X	"",			""
X};
X
SHAR_EOF
chmod 0660 cvt_id.h || echo "restore of cvt_id.h fails"
sed 's/^X//' << 'SHAR_EOF' > decl_out.c &&
X#include "misc.h"
X#include "defs.h"
X#include "cvt.h"
X#include "struct.h"
X#include "tokens.h"
X
Xextern	char	*text_ptr;
Xextern	int	at_decl_count;
Xextern	char	at_decl_list[MAX_AT_DECLS][MAX_TOKEN_LENGTH];
X
X/*
X *	Output *<name> if use_parens == NULL, else (*<name>).
X */
Xout_pointer(name, use_parens)
XTOKEN	*name;
XBOOLEAN	use_parens;
X{
X		/* Use parentheses? */
X	if (use_parens) {
X			/* Yes - make it (*name) */
X		out_str("(*");
X		out_token_name(name);
X		out_char(')');
X	} else {
X			/* No - make it *name */
X		out_char('*');
X		out_token_name(name);
X	}
X}
X
X/*
X *	Output array bound (if any)
X */
Xout_bound(bound)
XTOKEN	*bound;
X{
X	if (bound) {
X		out_char('[');
X		out_token(bound);
X		out_char(']');
X	}
X}
X
X/*
X *	Output a declaration type.
X */
Xout_decl_type(decl_ptr)
XDECL_MEMBER	*decl_ptr;
X{
X	if (decl_ptr->type->token_type != STRUCTURE) {
X		out_type(decl_ptr->type->token_type);
X	} else {
X		out_struct(decl_ptr->struct_list);
X	}
X}
X
X/*
X *	Output structure contents.
X */
Xout_struct(el_ptr)
XDECL_MEMBER	*el_ptr;
X{
X	DECL_ID		*var_ptr;
X
X	out_str("struct {");
X
X	while (el_ptr) {
X			/* Use initial white space before type */
X		var_ptr = el_ptr->name_list;
X		if (var_ptr)
X			out_must_white(var_ptr->name);
X
X		out_decl_type(el_ptr);
X		out_char(' ');
X
X		while (var_ptr) {
X			out_token_name(var_ptr->name);
X			out_bound(el_ptr->array_bound);
X			var_ptr = var_ptr->next_var;
X			if (var_ptr) {
X				out_char(',');
X				out_must_white(var_ptr->name);
X			}
X		}
X		if ((el_ptr = el_ptr->next_member) != NULL)
X			out_char(';');
X	}
X	out_char('}');
X}
X
X/*
X *	Output C declaration list member.
X */
Xout_decl_member(decl_list, decl_token)
XDECL_MEMBER	*decl_list;
XTOKEN		*decl_token;
X{
X	int	i;
X	TOKEN	token, tmp_token;
X	int	token_class;
X	int	name_count;
X	char	count_str[8];
X	DECL_ID	*var_ptr;
X	char	*tmp_white_start, *tmp_white_end;
X	char	*tmp_text_ptr;
X	BOOLEAN	typedefed, is_at;
X	int	string_len, string_size;
X	char	*string_ptr;
X
X		/* Output characters up to CR */
X	out_pre_white(decl_token);
X
X	if (decl_list->type->token_type == LABEL)
X			/* Ignore label declarations */
X		return;
X
X	var_ptr = decl_list->name_list;
X
X	if (decl_list->type->token_type == LITERALLY) {
X			/* Make sure we're at start of new line */
X		out_pre_white(var_ptr->name);
X		out_to_start();
X
X			/* Convert to a #define */
X		out_str("#define ");
X		out_cvt_name(var_ptr->name);
X		out_char(' ');
X		out_str(decl_list->literal);
X/*
X		out_str("\n");
X*/
X		return;
X	}
X
X	var_ptr->name->white_space_start = decl_token->white_space_start;
X	var_ptr->name->white_space_end = decl_token->white_space_end;
X
X		/* Swap white space between type and first identifier */
X		/* and eat any new_lines prior to first identifier */
X	tmp_white_start = decl_list->type->white_space_start;
X	tmp_white_end = decl_list->type->white_space_end;
X
X	while ((tmp_white_start < tmp_white_end) && (*tmp_white_start < ' '))
X		tmp_white_start++;
X
X	decl_list->type->white_space_start = var_ptr->name->white_space_start;
X	var_ptr->name->white_space_start = tmp_white_start;
X	decl_list->type->white_space_end = var_ptr->name->white_space_end;
X	var_ptr->name->white_space_end = tmp_white_end;
X
X	out_white_space(decl_list->type);
X
X	if (decl_list->attributes == EXTERNAL) {
X		out_str("extern ");
X
X			/* Check if declared AT in another module */
X		for (i = 0; i < at_decl_count; i++)
X			if (!strcmp(var_ptr->name->token_name, at_decl_list[i]))
X					/* Yes - flag as so */
X				var_ptr->is_ext_at = TRUE;
X	} else
X
X	if (decl_list->initialization == DATA) {
X		out_str(TYPE_DATA);
X		out_char(' ');
X	}
X
X
X	is_at = (decl_list->at_ptr != NULL) || var_ptr->is_ext_at;
X
X		/* Determine if a structure with an AT attribute */
X	typedefed = (decl_list->type->token_type == STRUCTURE) && is_at;
X
X		/* Output type */
X		/* Is this a structure with an AT attribute? */
X	if (typedefed) {
X			/* Yes - output typedefed structure */
X		out_str("typedef ");
X		out_struct(decl_list->struct_list);
X		out_must_white(var_ptr->name);
X#ifdef USE_DEFINES
X		out_char('_');
X#endif
X		out_cvt_name(var_ptr->name);
X		if (decl_list->array_bound)
X			out_bound(decl_list->array_bound);
X		out_str(";\n");
X		out_white_space(decl_token);
X#ifdef USE_DEFINES
X		out_char('_');
X#endif
X		out_cvt_name(var_ptr->name);
X	} else
X		out_decl_type(decl_list);
X
X		/* Walk through name list */
X	name_count = 0;
X	while (var_ptr) {
X		if (is_at) {
X				/* AT (<expression>) -
X				   OK... don't panic...
X				   we can handle this
X				*/
X/*
X * Output:
X *	<type> *<ident> = (<type> *) <AT expr> + name_count
X *
X * NOTE: BASED variables are not dealt with.
X */
X			out_must_white(var_ptr->name);
X				/* Is this an array? */
X			if ((decl_list->array_bound) && !typedefed)
X					/* Yes - output ( *<ident> ) */
X				out_char('(');
X			out_char('*');
X#ifdef USE_DEFINES
X				/* Output case converted name */
X			out_cvt_name(var_ptr->name);
X#else
X			out_token_name(var_ptr->name);
X#endif
X			if ((decl_list->array_bound) && !typedefed) {
X				out_char(')');
X					/* Output array bound (if any) */
X				out_bound(decl_list->array_bound);
X			}
X
X			if (decl_list->attributes != EXTERNAL) {
X			    out_str(" = (");
X				/* Is this a structure? */
X			    if (decl_list->type->token_type == STRUCTURE) {
X					/* Yes - output structure name prefix */
X#ifdef USE_DEFINES
X				out_char('_');
X#endif
X				out_cvt_name(decl_list->name_list->name);
X			    } else
X				out_decl_type(decl_list);
X			    out_str(" *) ");
X
X			    out_str(decl_list->at_ptr);
X			    if (name_count) {
X				(void) sprintf(count_str, " + %d", name_count);
X				out_str(count_str);
X			    }
X			}
X		} else {
X				/* Not an AT expression (whew!) */
X			out_must_white(var_ptr->name);
X
X				/* Is variable based? */
X			if (var_ptr->based_name) {
X					/* Yes - Output **name = */
X					/*	(type **) &based_name */
X				if (decl_list->array_bound) {
X						/* Use (**name)[] */
X					out_str("(**");
X					out_token_name(var_ptr->name);
X					out_str(")[]");
X				} else {
X					out_str("**");
X					out_token_name(var_ptr->name);
X				}
X
X				out_str(" = (");
X				out_decl_type(decl_list);
X				out_str(" **) &");
X				out_token_name(var_ptr->based_name);
X			} else
X
X			if (decl_list->type->token_type == POINTER) {
X					/* Yes - if based on an array */
X					/* output (*name) else output *name */
X				out_pointer(var_ptr->name,
X					(BOOLEAN) decl_list->array_bound);
X			} else {
X					/* Output variable name */
X				out_token_name(var_ptr->name);
X
X					/* Output array bound (if any) */
X				out_bound(decl_list->array_bound);
X			}
X		}
X
X			/* Get next name */
X		if ((var_ptr = var_ptr->next_var) != NULL) {
X			out_char(',');
X			name_count++;
X		}
X	}
X
X		/* Check for INITIAL or DATA initializers */
X	if (decl_list->initialization != NONE) {
X		out_str(" = ");
X			/* Point back to initializer string */
X		tmp_text_ptr = text_ptr;
X		text_ptr = decl_list->init_ptr;
X		if (decl_list->array_bound) {
X			out_char('{');
X				/* Array - determine if just a single string */
X			switch (decl_list->type->token_type) {
X
X			case BYTE :
X				string_size = SIZE_BYTE;
X				break;
X
X			case WORD :
X				string_size = SIZE_WORD;
X				break;
X
X			case DWORD :
X				string_size = SIZE_DWORD;
X				break;
X
X			case STRUCTURE :
X/*
X *  Oh, SH-T!!  fake it!
X */
X				string_size = SIZE_BYTE;
X				break;
X
X			default :
X				string_size = 0;
X			}
X
X			if (string_size && (get_token(&token) == STRING) &&
X				(get_token(&tmp_token) == RIGHT_PAREN)) {
X					/* Single string - break up into */
X					/* Pieces of sizeof(<type>) size */
X				string_ptr = token.token_name;
X				string_len = token.token_length;
X				while (string_len) {
X					out_str_const(string_ptr, string_size);
X					if (string_size > string_len)
X						string_size = string_len;
X					string_ptr += string_size;
X					if (string_len -= string_size)
X						out_char(',');
X				}
X			} else {
X					/* Point back to init string */
X				text_ptr = decl_list->init_ptr;
X				do {
X					token_class = parse_expression(&token);
X					if (token_class == COMMA)
X						out_token(&token);
X				} while (token_class == COMMA);
X			}
X
X			out_char('}');
X				/* Point past init string */
X			text_ptr = token.token_start + token.token_length + 2;
X			token_class = get_token(&token);
X		} else {
X			token_class = parse_expression(&token);
X		}
X		if (token_class != RIGHT_PAREN)
X			parse_error("')' expected");
X		text_ptr = tmp_text_ptr;
X	}
X
X	out_char(';');
X
X#ifdef USE_DEFINES
X		/* Walk through name list and check for BASED variables */
X	var_ptr = decl_list->name_list;
X	while (var_ptr) {
X			/* See if variable is BASED */
X		if (var_ptr->based_name) {
X				/* Make sure we're at start of new line */
X			out_to_start();
X			out_str("#define");
X			out_must_token(var_ptr->based_name);
X			out_white_space(var_ptr->name);
X			out_str("(*");
X			out_token_name(var_ptr->name);
X			out_str(")\n");
X		}
X
X			/* See if variable is AT */
X		if (is_at) {
X				/* Make sure we're at start of new line */
X			out_to_start();
X			out_str("#define");
X			out_must_token(var_ptr->name);
X			out_white_space(var_ptr->name);
X			out_str("(*");
X			out_cvt_name(var_ptr->name);
X			out_str(")\n");
X		}
X
X		var_ptr = var_ptr->next_var;
X	}
X#endif
X}
X
Xout_decl(decl)
XDECL		*decl;
X{
X	DECL_MEMBER	*decl_list;
X
X	while (decl) {
X		for (decl_list = decl->decl_list; decl_list;
X				decl_list = decl_list->next_member)
X			out_decl_member(decl_list, decl->decl_token);
X		decl = decl->next_decl;
X	}
X}
SHAR_EOF
chmod 0660 decl_out.c || echo "restore of decl_out.c fails"
sed 's/^X//' << 'SHAR_EOF' > declare.c &&
X#include "misc.h"
X#include "defs.h"
X#include "cvt.h"
X#include "struct.h"
X#include "tokens.h"
X
Xextern	char	*text_ptr;
Xextern	char	*out_string;
X
X/*
X *	Routines to process DECLARE statements.
X */
X
X/*
X *	Skip to closing right parenthesis
X */
Xfind_right_paren()
X{
X	TOKEN	token;
X	int	token_class;
X	int	paren_count;
X
X	paren_count = 1;
X	do {
X		token_class = get_token(&token);
X		if (token_class == LEFT_PAREN)
X			paren_count++;
X		else
X		if (token_class == RIGHT_PAREN)
X			paren_count--;
X	} while (paren_count);
X}
X
X/*
X *	Copy an element from source to destination
X */
Xelement_copy(src, dest)
XDECL_MEMBER	*src, *dest;
X{
X		/* Don't copy name list */
X	dest->name_list = NULL;
X		/* Don't copy link */
X	dest->next_member = NULL;
X	dest->literal = src->literal;
X	dest->array_bound = src->array_bound;
X	dest->type = src->type;
X	dest->attributes = src->attributes;
X	dest->initialization = src->initialization;
X	dest->at_ptr = src->at_ptr;
X	dest->init_ptr = src->init_ptr;
X	if (src->struct_list)
X		element_copy(src->struct_list, dest->struct_list);
X}
X
X/*
X *	Generate a linked list of variables of the form:
X *		<id> [BASED <id>[.<id>]] or
X *		( <id> [BASED <id>[.<id>]] [ ,<id> [BASED <id>[.<id>]] ] ... )
X *	Return token following variable list.
X */
Xget_var_list(list_ptr, sep_token)
XDECL_ID	**list_ptr;
XTOKEN	*sep_token;
X{
X	DECL_ID	*var_ptr, *last_var;
X	TOKEN	*token;
X	int	token_class;
X	BOOLEAN	multi_list;
X	char	*par_white_start, *par_white_end;
X
X	*list_ptr = NULL;
X		/* Get first token */
X	get_token_ptr(&token);
X	token_class = get_token(token);
X
X		/* Determine if <var> or list of ( <var> [,<var>] ... ) */
X	if (token_class == LEFT_PAREN) {
X			/* List of ( <var> [,<var>] ... ) */
X		multi_list = TRUE;
X
X			/* Use white space before '(' for first identifier */
X		par_white_start = token->white_space_start;
X		par_white_end = token->white_space_end;
X
X			/* Get first identifier */
X		token_class = get_token(token);
X		token->white_space_start = par_white_start;
X		token->white_space_end = par_white_end;
X	} else
X			/* <var> */
X		multi_list = FALSE;
X
X		/* Process identifier list */
X	last_var = NULL;
X	while (1) {
X		if (token_class != IDENTIFIER) {
X			parse_error("Identifier expected");
X			free_var_list(*list_ptr);
X			free((char *) token);
X			*list_ptr = NULL;
X			return ERROR;
X		}
X
X			/* Get a variable structure */
X		get_var_ptr(&var_ptr);
X
X		if (*list_ptr == NULL)
X				/* Point to first variable */
X			*list_ptr = var_ptr;
X
X		if (last_var)
X			last_var->next_var = var_ptr;
X		last_var = var_ptr;
X
X			/* Save variable name */
X		var_ptr->name = token;
X
X			/* Check for BASED */
X		token_class = get_token(sep_token);
X
X		if ((token_class == RESERVED) &&
X			(sep_token->token_type == BASED)) {
X				/* BASED <id>[ .<id> ] */
X				/* Get based name */
X			get_token_ptr(&token);
X			token_class = get_token(token);
X			if (token_class != IDENTIFIER) {
X				parse_error("Identifier expected");
X				free_var_list(*list_ptr);
X				free((char *) token);
X				*list_ptr = NULL;
X				return ERROR;
X			}
X			token_class = parse_simple_variable(token, sep_token);
X
X#ifdef USE_DEFINES
X				/* Swap variable name with based name */
X			var_ptr->based_name = var_ptr->name;
X			var_ptr->name = token;
X#else
X			var_ptr->based_name = token;
X#endif
X		}
X
X		if (!multi_list)
X			return token_class;
X
X		if (token_class != COMMA)
X			break;
X
X			/* Get next variable */
X		get_token_ptr(&token);
X		token_class = get_token(token);
X	}
X
X	if (token_class == RIGHT_PAREN) {
X			/* Get next token */
X		token_class = get_token(sep_token);
X		return token_class;
X	} else {
X		parse_error("')' expected");
X		free_var_list(*list_ptr);
X		*list_ptr = NULL;
X		return ERROR;
X	}
X}
X
X/*
X *	Parse a structure declaration of the form:
X *	STRUCTURE ( <member> [ ,<member> ] ... )
X *		where:
X *	<member> ::= { <id> | ( <id> [ ,<id> ] ... ) } [ ( <numeric> ) ] <type>
X */
Xparse_structure(list_ptr)
XDECL_MEMBER	**list_ptr;
X{
X	DECL_MEMBER	*struct_ptr, *last_struct;
X	TOKEN		token;
X	int		token_class;
X
X	*list_ptr = NULL;
X
X		/* Get left paren */
X	token_class = get_token(&token);
X	if (token_class != LEFT_PAREN) {
X		parse_error("'(' expected");
X		return;
X	}
X
X	last_struct = NULL;
X	do {
X			/* Get a DECL_MEMBER structure */
X		get_element_ptr(&struct_ptr);
X
X		if (*list_ptr == NULL)
X				/* Point to first structure */
X			*list_ptr = struct_ptr;
X
X		if (last_struct)
X			last_struct->next_member = struct_ptr;
X		last_struct = struct_ptr;
X
X			/* Get variable list */
X		token_class = get_var_list(&struct_ptr->name_list, &token);
X
X			/* Get type and optional array designator */
X		get_token_ptr(&struct_ptr->type);
X		token_class = parse_type(struct_ptr, &token);
X
X			/* Get seperator */
X		token_class = get_token(&token);
X	} while (token_class == COMMA);
X
X	if (token_class != RIGHT_PAREN) {
X		parse_error("'(' expected");
X		free_decl_list(*list_ptr);
X		*list_ptr = NULL;
X		return;
X	}
X}
X
X/*
X *	Parse type and optional array designator.
X *	Passed initial token.
X *	Returns RESERVED if appropriate type found, else returns END_OF_LINE.
X */
Xparse_type(el_ptr, token)
XDECL_MEMBER	*el_ptr;
XTOKEN		*token;
X{
X	TOKEN	*temp_token;
X	int	token_class;
X
X	token_class = token->token_class;
X	if (token_class == LEFT_PAREN) {
X			/* Array specifier */
X			/* Get numeric or '*' */
X		get_token_ptr(&temp_token);
X		token_class = get_token(temp_token);
X
X		if ((token_class == NUMERIC) ||
X			((token_class == OPERATOR) &&
X				(temp_token->token_type == TIMES))) {
X			if (token_class != NUMERIC)
X				/* array(*) specified - ignore '*' */
X				temp_token->token_name[0] = '\0';
X
X				/* Save array bound token */
X			el_ptr->array_bound = temp_token;
X		} else {
X			parse_error("Illegal array bound");
X			free((char *) temp_token);
X			return ERROR;
X		}
X
X			/* Get right paren */
X		token_class = get_token(token);
X		if (token_class != RIGHT_PAREN) {
X			parse_error("')' expected");
X			free((char *) temp_token);
X			return ERROR;
X		}
X
X			/* Get type */
X		token_class = get_token(token);
X	}
X
X	if ((token_class == RESERVED) && (token->token_type >= BYTE) &&
X					 (token->token_type <= STRUCTURE)) {
X
X			/* Save type token */
X		token_copy(token, el_ptr->type);
X
X		if (token->token_type == STRUCTURE) {
X				/* Get structure list */
X			parse_structure(&el_ptr->struct_list);
X		}
X		return token_class;
X	} else {
X		parse_error("Illegal type");
X		return ERROR;
X	}
X}
X
X/*
X *	Parse a DECLARE element.
X *	Return token terminating DECLARE element.
X */
Xget_element(element, token)
XDECL_MEMBER	**element;
XTOKEN		*token;
X{
X	DECL_MEMBER	*el_ptr;
X	TOKEN		temp_token, eof_token;
X	int		token_class;
X	char		*tmp_text_ptr;
X	char		*tmp_out_string;
X
X	char		*get_mem();
X
X	get_element_ptr(element);
X
X		/* Point to element */
X	el_ptr = *element;
X
X		/* Get name list */
X	token_class = get_var_list(&el_ptr->name_list, token);
X
X		/* Malloc space for type */
X	get_token_ptr(&el_ptr->type);
X
X	if (token_class == RESERVED)
X	    switch (token->token_type) {
X
X	    case LABEL :
X			/* LABEL declaration */
X		token_copy(token, el_ptr->type);
X
X			/* Check for PUBLIC or EXTERNAL */
X		token_class = get_token(token);
X		if ((token_class == RESERVED) &&
X			((token->token_type == PUBLIC) ||
X			 (token->token_type == EXTERNAL)))
X				/* Indeed, who cares? */
X			token_class = get_token(token);
X		return token_class;
X
X	    case LITERALLY :
X		token_copy(token, el_ptr->type);
X
X			/* Check for 'string' */
X		if (get_token(token) != STRING) {
X			parse_error("String expected");
X			free_decl_list(el_ptr);
X			return ERROR;
X		}
X
X		el_ptr->literal = get_mem(MAX_LITERAL_SIZE);
X#ifdef PARSE_LITERALS
X			/* Parse literal string if only one token in string */
X		tmp_text_ptr = text_ptr;
X		text_ptr = token->token_name;
X
X			/* Parse token in string */
X		if (get_token(&temp_token) == END_OF_FILE)
X			el_ptr->literal[0] = '\0';
X		else
X		if (get_token(&eof_token) == END_OF_FILE) {
X				/* Single token literal */
X			(void) strcpy(el_ptr->literal, temp_token.token_name);
X				/* Save parsed token */
X			get_token_ptr(&el_ptr->literal_token);
X			token_copy(&temp_token, el_ptr->literal_token);
X		} else
X			(void) strcpy(el_ptr->literal, token->token_name);
X
X		text_ptr = tmp_text_ptr;
X#else
X			/* Put string in literal */
X		(void) strcpy(el_ptr->literal, token->token_name);
X#endif
X
X			/* Return following token */
X		token_class = get_token(token);
X		return token_class;
X	}
X
X	if (parse_type(el_ptr, token) != RESERVED) {
X			/* Error occurred */
X		free_decl_list(el_ptr);
X		return END_OF_LINE;
X	}
X
X		/* Process attribute information (if any) */
X		/* Check for EXTERNAL [ DATA ] */
X	token_class = get_token(token);
X	if (token_class != RESERVED)
X		return token_class;
X
X	if (token->token_type == EXTERNAL) {
X		el_ptr->attributes = EXTERNAL;
X
X			/* Check for DATA attribute */
X		token_class = get_token(token);
X		if (token_class == RESERVED) {
X			if (token->token_type == DATA) {
X/*
X *	Ignore attribute
X *				el_ptr->initialization = DATA;
X */
X				token_class = get_token(token);
X			} else {
X				parse_error("Illegal attribute");
X				free_decl_list(el_ptr);
X				return ERROR;
X			}
X		}
X
X		return token_class;
X	} else
X
X		/* Check for PUBLIC */
X	if (token->token_type == PUBLIC) {
X		el_ptr->attributes = PUBLIC;
X		token_class = get_token(token);
X	}
X
X	if (token_class != RESERVED)
X		return token_class;
X
X		/* Check for AT ( <expr> ) */
X	if (token->token_type == AT) {
X			/* Check for '(' */
X		token_class = get_token(token);
X
X		if (token_class != LEFT_PAREN) {
X				parse_error("'(' expected");
X				free_decl_list(el_ptr);
X				return ERROR;
X		}
X
X			/* Generate a string for the AT expression */
X		el_ptr->at_ptr = get_mem(MAX_AT_EXPR_SIZE);
X		el_ptr->at_ptr[0] = '\0';
X		tmp_out_string = out_string;
X		out_string = el_ptr->at_ptr;
X
X			/* Parse the expression into at_ptr */
X		token_class = parse_expression(token);
X		if (token_class != RIGHT_PAREN) {
X			parse_error("')' expected");
X			free_decl_list(el_ptr);
X			return ERROR;
X		}
X		out_string = tmp_out_string;
X		token_class = get_token(token);
X	}
X
X	if (token_class != RESERVED)
X		return token_class;
X
X		/* Check for INITIAL or DATA ( <expr> ) */
X	if ((token->token_type == INITIAL) ||
X		(token->token_type == DATA)) {
X
X		el_ptr->initialization = token->token_type;
X
X			/* Check for '(' */
X		token_class = get_token(token);
X
X		if (token_class != LEFT_PAREN) {
X				parse_error("'(' expected");
X				free_decl_list(el_ptr);
X				return ERROR;
X		}
X
X		el_ptr->init_ptr = text_ptr;
X			/* Skip to ')' */
X		find_right_paren();
X		token_class = get_token(token);
X	}
X	return token_class;
X}
X
X/*
X *	Parse a DECLARE list.
X *	Passed a pointer to a DECL, returns with DECL filled.
X */
Xget_decl_list(decl)
XDECL	*decl;
X{
X	DECL_MEMBER	*el_ptr, *decl_ptr;
X	TOKEN		token;
X	int		token_class;
X
X	decl->decl_list = NULL;
X	decl->next_decl = NULL;
X	decl_ptr = NULL;
X
X	do {
X			/* Get a declaration element */
X		token_class = get_element(&el_ptr, &token);
X
X		if (decl->decl_list == NULL)
X			decl->decl_list = el_ptr;
X
X			/* Link previous element */
X		if (decl_ptr)
X			decl_ptr->next_member = el_ptr;
X		decl_ptr = el_ptr;
X	} while (token_class == COMMA);
X}
X
X/*
X *	Parse a DECLARE statement.
X */
Xparse_declare(first_token)
XTOKEN	*first_token;
X{
X	DECL		decl;
X
X	decl.decl_token = first_token;
X	get_decl_list(&decl);
X	out_decl(&decl);
X	add_to_context(decl.decl_list);
X}
SHAR_EOF
chmod 0660 declare.c || echo "restore of declare.c fails"
sed 's/^X//' << 'SHAR_EOF' > defs.h &&
X/*
X *	Maximum number of characters in a token
X */
X#define	MAX_TOKEN_LENGTH 512
X
X/*
X *	Maximum number of characters in an individual DO CASE statement
X */
X#define MAX_CASE_STATEMENT_SIZE 10240
X
X/*
X *	Maximum number of characters in an AT expression
X */
X#define MAX_AT_EXPR_SIZE 128
X
X/*
X *	Maximum number of characters in a literal string
X */
X#define MAX_LITERAL_SIZE 512
X
X/*
X *	Maximum number of identifier names in at_decl.cvt
X */
X#define MAX_AT_DECLS 64
SHAR_EOF
chmod 0660 defs.h || echo "restore of defs.h fails"
sed 's/^X//' << 'SHAR_EOF' > error.c &&
X#include <stdio.h>
X#include <string.h>
X#include "misc.h"
X#include "defs.h"
X#include "cvt.h"
X#include "struct.h"
X#include "tokens.h"
X#include "tkn_ext.h"
X
Xextern	BOOLEAN	syntax_error;
X
Xextern	char	*text_ptr;
Xextern	int	line_count;
Xextern	char	*line_ptr;
Xextern	char	current_file_name[];
X
X/*
X *	parse_mesg() -	Print given message, message type, and current
X *			line number.  Skip to error_eol.
X */
Xparse_mesg(error_string, error_type, error_eol)
Xchar	*error_string, *error_type;
Xchar	error_eol;
X{
X	char	*err_ptr;
X	int	i, offset;
X	TOKEN	token;
X
X	syntax_error = TRUE;
X
X	offset = text_ptr - line_ptr - 1;
X
X		/* Find end of line */
X	for (err_ptr = line_ptr; (*err_ptr != '\0') &&
X				 (*err_ptr != LF); err_ptr++) ;
X
X	if (*error_string) {
X		(void) fprintf(stderr, "\n%s - Parse %s: %s.\nOccurred at line %d near:\n",
X			current_file_name, error_type, error_string, line_count);
X
X			/* Print offending line */
X		(void) fwrite(line_ptr, err_ptr - line_ptr + 1, 1, stderr);
X
X		for (i = 0; i < offset; i++)
X			if (line_ptr[i] < ' ')
X				(void) fputc(line_ptr[i], stderr);
X			else
X				(void) fputc(' ', stderr);
X		(void) fputc('^', stderr);
X
X		if (*err_ptr == '\0')
X			(void) fputc(LF, stderr);
X	}
X
X	if (*err_ptr != '\0')
X		err_ptr++;
X
X		/* Skip to end-of-line */
X	if (error_eol == '\0')
X		return;
X	else
X
X	if (error_eol == LF) {
X		text_ptr = err_ptr;
X		line_ptr = err_ptr;
X		line_count++;
X	} else {
X
X		if (*(text_ptr - 1) != ';') {
X			do {
X				i = get_token(&token);
X			} while ((i != END_OF_FILE) && (i != END_OF_LINE));
X		}
X
X			/* Point at end of line */
X		text_ptr--;
X	}
X}
X
X/*
X *	parse_error() -	Print given error message and current line number.
X *			Called when an unrecognised or unprocessable token
X *			appears.
X */
Xparse_error(error_string)
Xchar	*error_string;
X{
X	if (syntax_error)
X			/* Already had an error on this line */
X		return;
X
X	parse_mesg(error_string, "error", END_OF_LINE);
X}
X
X/*
X *	Do a parse_error(), but move to END_OF_LINE, not ';'
X */
Xcontrol_error(error_string)
Xchar	*error_string;
X{
X#ifdef IGNORE_CONTROL_ERRORS
X	parse_mesg("", "", LF);
X#else
X	parse_mesg(error_string, "error", LF);
X#endif
X}
X
X/*
X *	parse_warning - Generate a warning message
X */
Xparse_warning(warning_string)
Xchar	*warning_string;
X{
X	parse_mesg(warning_string, "warning", '\0');
X}
X
SHAR_EOF
chmod 0660 error.c || echo "restore of error.c fails"
sed 's/^X//' << 'SHAR_EOF' > io.c &&
X#include <stdio.h>
X#ifdef IBMPC
X#include <stdlib.h>
X#endif
X#include "misc.h"
X#include "defs.h"
X#include "cvt.h"
X#include "struct.h"
X#include "tokens.h"
X
Xchar	*out_string;
Xchar	last_out_ch;
X
Xchar	*str_shifts[] = { "0", "8", "16", "24" };
X
Xextern	char	*text_buffer, *text_ptr;
Xextern	int	line_count;
Xextern	int	file_depth;
Xextern	FILE	*ofd;
X
Xextern	BOOLEAN	parsing_literal;
Xextern	TOKEN	literal_token;
X
X/*
X *	Output data of specified length.
X *	If out_string is not NULL, append string to out_string.
X *	Otherwise write string to stdout.
X */
Xout_data(string, length)
Xchar	*string;
Xint	length;
X{
X	if (length) {
X		if (out_string)
X			(void) strncat(out_string, string, length);
X		else
X		if (file_depth == 1)
X#ifdef DEBUG
X			(void) fwrite(string, length, 1, stdout);
X#else
X			(void) fwrite(string, length, 1, ofd);
X#endif
X		else
X			return;
X
X			/* Save last character output */
X		last_out_ch = *(string + length - 1);
X	}
X}
X
X/*
X *	Print white space
X */
Xout_white_space(token)
XTOKEN	*token;
X{
X	int	length;
X
X		/* Compute length of white space */
X	length = token->white_space_end - token->white_space_start;
X
X	if (length)
X		out_data(token->white_space_start, length);
X}
X
X/*
X *	Print white space, if any.  If start of white space string is not
X *	white, prefix with a space.
X */
Xout_must_white(token)
XTOKEN	*token;
X{
X	if (!is_white(*(token->white_space_start)))
X		out_char(' ');
X	out_white_space(token);
SHAR_EOF
echo "End of part 1, continue with part 2"
echo "2" > s2_seq_.tmp
exit 0