aboutsummaryrefslogtreecommitdiff
path: root/unix/boot/spp/xpp/decl.c
blob: b5c6477430c9cc7b686cd3f7658c25fb7743735f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
 */

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "xpp.h"

#define	import_spp
#include <iraf.h>

#ifndef SZ_SBUF
#define	SZ_SBUF		4096		/* max chars in proc. decls.	*/
#endif
#define	SZ_TOKEN	63		/* max chars in a token		*/
#define	MAX_SYMBOLS	300		/* max symbol table entries	*/
#define	SPMAX		(&sbuf[SZ_SBUF-1])
#define	UNDECL		0

/*
 * DECL.C -- A package of routines for parsing argument lists and declarations
 * and generating the Fortran (actually, RPP) declarations required to compile
 * a procedure.  The main functions of this package at present are to remove
 * arbitrary limitations on the ordering of argument declarations imposed by
 * Fortran, and to perform various compile time checks on all declarations.
 * Specifically, we allow scalar arguments to be used to dimension array
 * arguments before the scalar arguments are declared, and we check for
 * multiple declarations of the same object.
 *
 * Package Externals:
 *
 *	    d_newproc (name, type)	process procedure declaration
 *	d_declaration (typestr)		process typed declaration statement
 *	    d_codegen (fp)		output declarations for sym table
 *	    d_runtime (text)		return any runtime initialization text
 *
 *	*symbol =  d_enter (symbol, dtype, flags)
 *	*symbol = d_lookup (symbol)
 *
 * The external procedures YY_INPUT() and YY_UNPUT() are called to get/putpack
 * characters from the input.
 */

extern	int linenum[];			/* line numbers in files	*/
extern	int istkptr;			/* istk pointer			*/

struct symbol {
	char	*s_name;		/* symbol name			*/
	char	*s_dimstr;		/* dimension string if array	*/
	short	s_dtype;		/* datatype (0 until declared)	*/
	short	s_flags;		/* type flags			*/
};

#define	S_ARGUMENT	001		/* symbol is an argument	*/
#define	S_ARRAY		002		/* symbol is an array		*/
#define	S_FUNCTION	004		/* symbol is a function()	*/
#define	S_EXTERN	010		/* symbol is an external	*/

static	char sbuf[SZ_SBUF+1];		/* string buffer		*/
static	char *nextch = sbuf;		/* next location in sbuf	*/
static	char procname[SZ_FNAME+1];	/* procedure name		*/
static	int  proctype;			/* procedure type if function	*/
static	struct symbol sym[MAX_SYMBOLS];	/* symbol table			*/
static	int nsym = 0;			/* number of symbols		*/

struct	symbol *d_enter();
struct	symbol *d_lookup();

extern  void error (int errcode, char *errmsg);
extern  void xpp_warn (char *warnmsg);
extern  int  yy_input (void);
extern  void yy_unput (char ch);


void  d_newproc (char *name, int dtype);
int   d_declaration (int dtype);
void  d_codegen (register FILE *fp);
void  d_runtime (char *text);
void  d_makedecl (struct symbol *sp, FILE *fp);
struct symbol *d_enter (char *name, int dtype, int flags);
struct symbol *d_lookup (char *name);
void  d_chksbuf (void);
int   d_gettok (char *tokstr, int maxch);
void  d_declfunc (struct symbol *sp, FILE *fp);




/* D_NEWPROC -- Process a procedure declaration.  The name of the procedure
 * is passed as the single argument.  The input stream is left positioned
 * with the ( of the argument list as the next token (if present).  INPUT is
 * called repeatedly to read the remainder of the declaration, which may span
 * several lines.  The symbol table is cleared whenever a new procedure
 * declaration is started.
 */
void
d_newproc (name, dtype)
char	*name;			/* procedure name		*/
int	dtype;			/* procedure type (0 if subr)	*/
{
	register int	token;
	char	tokstr[SZ_TOKEN+1];



	/* Print procedure name to keep the user amused in case the file
	 * is large and the machine slow.
	 */
	fprintf (stderr, "   %s:\n", name);
	fflush (stderr);

	strncpy (procname, name, SZ_FNAME);
	proctype = dtype;
	nextch = sbuf;
	nsym = 0;

	/* Check for null argument list. */
	if (d_gettok(tokstr,SZ_TOKEN) != '(')
	    return;

	/* Process the argument list.
	 */
	while ((token = d_gettok(tokstr,SZ_TOKEN)) != ')') {
	    if (isalpha(token)) {
		/* Enter argument name into the symbol table.
		 */
		if (d_lookup (tokstr) != NULL) {
		    char lbuf[200];
		    sprintf (lbuf, "%s.%s multiply declared",
			procname, tokstr);
		    xpp_warn (lbuf);
		} else
		    d_enter (tokstr, UNDECL, S_ARGUMENT);
	    } else if (token == '\n') {
		linenum[istkptr]++;
		continue;
	    } else if (token == ',') {
		continue;
	    } else
		error (XPP_SYNTAX, "bad syntax in procedure argument list");
	}
}


/* D_DECLARATION -- Process a declaration statement.  This is any statement
 * of the form
 *
 *	type	obj1, obj2, ..., objn
 *
 * ignoring comments and newlines following commas.  The recognized types are
 *
 *	bool, char, short, int, long, real, double, complex, pointer, extern
 *
 * If "obj" is followed by "()" the function type bit is set.  If followed
 * by "[...]" the array bit is set and the dimension string is accumulated,
 * converting [] into (), adding 1 for char arrays, etc. in the process.
 * Each OBJ identifier is entered into the symbol table with its attributes.
 */
int
d_declaration (int dtype)
{
	register struct	symbol *sp = NULL;
	register char	ch;
	int	token, ndim;
	char	tokstr[SZ_TOKEN+1];

	while ((token = d_gettok(tokstr,SZ_TOKEN)) != '\n') {
	    if (isalpha(token)) {

#ifdef CYGWIN
	        {   if (strncmp ("procedure", tokstr, 9) == 0) { 
/*
      			extern char *yytext;
      			pushcontext (PROCSTMT);
      			d_gettok (yytext, SZ_TOKEN-1);
      			d_newproc (yytext, dtype);
*/
      			pushcontext (PROCSTMT);
      			d_gettok (tokstr, SZ_TOKEN-1);
      			d_newproc (tokstr, dtype);
                	return (1);
              	    }
	        }
#endif

		/* Enter argument or variable name into the symbol table.
		 * If symbol is already in table it must be an argument
		 * or we have a multiple declaration.
		 */
		if ((sp = d_lookup (tokstr)) != NULL) {
		    if (dtype == XTY_EXTERN)
			sp->s_flags |= S_EXTERN;
		    else if (sp->s_flags & S_ARGUMENT && sp->s_dtype == UNDECL)
			sp->s_dtype = dtype;
		    else {
			char lbuf[200];
			sprintf (lbuf, "%s.%s multiply declared",
			    procname, tokstr);
			xpp_warn (lbuf);
		    }
		} else
		    sp = d_enter (tokstr, dtype, 0);

		/* Check for trailing () or [].
		 */
		token = d_gettok (tokstr, SZ_TOKEN);

		switch (token) {
		case ',':
		case '\n':
		    yy_unput (token);
		    continue;

		case '(':
		    /* Function declaration.
		     */
		    if ((token = d_gettok(tokstr,SZ_TOKEN)) != ')') {
			yy_unput (token);
			error (XPP_SYNTAX,
			    "missing right paren in function declaration");
		    } 
		    sp->s_flags |= S_FUNCTION;
		    continue;

		case '[':
		    /* Array declaration.  Turn [] into (), add space for EOS
		     * if char array, set array bit for operand in symbol table.
		     */
		    sp->s_dimstr = nextch;
		    *nextch++ = '(';
		    ndim = 1;

		    while ((ch = yy_input()) != ']' && ch > 0) {
			if (ch == '\n') {
			    yy_unput (ch);
			    error (XPP_SYNTAX,
				"missing right bracket in array declaration");
			    break;
			} else if (ch == ',') {
			    /* Add one char for the EOS in the first axis of
			     * a multidimensional char array.
			     */
			    if (ndim == 1 && dtype == TY_CHAR)
				*nextch++ = '+', *nextch++ = '1';
			    *nextch++ = ',';
			    ndim++;
			} else if (ch == 'A') {
			    /* Turn [ARB] into [*] for array arguments. */
			    if ((ch = yy_input()) == 'R') {
				if ((ch = yy_input()) == 'B') {
				    *nextch++ = '*';
				    ndim++;
				    if (!(sp->s_flags & S_ARGUMENT)) {
					error (XPP_SYNTAX,
					    "local variable dimensioned ARB");
					break;
				    }
				} else {
				    *nextch++ = 'A';
				    *nextch++ = 'R';
				    yy_unput (ch);
				}
			    } else {
				*nextch++ = 'A';
				yy_unput (ch);
			    }
			} else
			    *nextch++ = ch;
		    }

		    if (ndim == 1 && dtype == TY_CHAR)
			*nextch++ = '+', *nextch++ = '1';

		    *nextch++ = ')';
		    *nextch++ = '\0';
		    d_chksbuf();

		    sp->s_flags |= S_ARRAY;
		    break;

		default:
		    error (XPP_SYNTAX, "declaration syntax error");
		}

	    } else if (token == ',') {
		/* Check for implied continuation on the next line.
		 */
		do {
		    ch = yy_input();
		} while (ch == ' ' || ch == '\t');

		if (ch == '\n')
		    linenum[istkptr]++;
		else
		    yy_unput (ch);

	    } else if (sp && (sp->s_flags & S_ARGUMENT)) {
		error (XPP_SYNTAX, "bad syntax in procedure argument list");
	    } else
		error (XPP_SYNTAX, "declaration syntax error");
	}

	yy_unput ('\n');

	return (0);
}


/* D_CODEGEN -- Output the RPP declarations for all symbol table entries.
 * Declare scalar arguments first, followed by array arguments, followed
 * by nonarguments.
 */
void
d_codegen (fp)
register FILE	*fp;
{
	register struct symbol *sp;
	register struct	symbol *top = &sym[nsym-1];
	extern	char *type_decl[];
	int	col;

	/* Declare the procedure itself.
	 */
	if (proctype) {
	    fputs (type_decl[proctype], fp);
	    fputs (" x$func ", fp);
	} else
	    fputs ("x$subr ", fp);

	fputs (procname, fp);
	fputs (" ", fp);

	/* Output the argument list.  Keep track of the approximate line length
	 * and break line if it gets too long for the second pass.
	 */
	fputs ("(", fp);
	col = strlen(procname) + 9;

	for (sp=sym;  sp <= top;  sp++)
	    if (sp->s_flags & S_ARGUMENT) {
		if (sp > sym) {
		    fputs (", ", fp);
		    col += 2;
		}
		col += strlen (sp->s_name);
		if (col >= 78) {
		    fputs ("\n\t", fp);
		    col = strlen (sp->s_name) + 1;
		}
		fputs (sp->s_name, fp);
	    }
	fputs (")\n", fp);

	/* Declare scalar arguments. */
	for (sp=sym;  sp <= top;  sp++)
	    if (sp->s_flags & S_ARGUMENT)
		if (!(sp->s_flags & S_ARRAY))
		    d_makedecl (sp, fp);

	/* Declare vector arguments. */
	for (sp=sym;  sp <= top;  sp++)
	    if (sp->s_flags & S_ARGUMENT)
		if (sp->s_flags & S_ARRAY)
		    d_makedecl (sp, fp);

	/* Declare local variables and externals. */
	for (sp=sym;  sp <= top;  sp++)
	    if (sp->s_flags & S_ARGUMENT)
	        continue;
	    else if (sp->s_flags & S_FUNCTION)
	        d_declfunc (sp, fp);
	    else
		d_makedecl (sp, fp);
}


/* D_RUNTIME -- Return any runtime procedure initialization statements,
 * i.e., statements to be executed at runtime when a procedure is entered,
 * in the given output buffer.
 */
void
d_runtime (char *text)
{
	/* For certain types of functions, ensure that the function value
	 * is initialized to a legal value, in case the procedure is exited
	 * without returning a value (e.g., during error processing).
	 */
	switch (proctype) {
	case XTY_REAL:
	case XTY_DOUBLE:
	    sprintf (text, "\t%s = 0\n", procname);
	    break;
	default:
	    text[0] = EOS;
	    break;
	}
}


/* D_MAKEDECL -- Output a single RPP symbol declaration.  Each declaration
 * is output on a separate line.
 */
void
d_makedecl (sp, fp)
register struct symbol *sp;	/* symbol table entry		*/
register FILE	*fp;		/* output file			*/
{
	extern	char *type_decl[];

	if (sp->s_dtype != UNDECL) {
	    fputs (type_decl[sp->s_dtype], fp);
	    fputs ("\t", fp);
	    fputs (sp->s_name, fp);
	    if (sp->s_flags & S_ARRAY)
		fputs (sp->s_dimstr, fp);
	    fputs ("\n", fp);
	}

	if (sp->s_flags & S_EXTERN) {
	    fputs (type_decl[XTY_EXTERN], fp);
	    fputs ("\t", fp);
	    fputs (sp->s_name, fp);
	    fputs ("\n", fp);
	}
}


/* D_ENTER -- Add a symbol to the symbol table.  Return a pointer to the
 * new symbol.
 */
struct symbol *
d_enter (name, dtype, flags)
char	*name;			/* symbol name			*/
int	dtype;			/* data type code		*/
int	flags;			/* flag bits			*/
{
	register struct	symbol *sp;


	sp = &sym[nsym];
	nsym++;
	if (nsym > MAX_SYMBOLS)
	    error (XPP_COMPERR, "too many declarations in procedure");

	sp->s_name = strcpy (nextch, name);
	nextch += strlen(name) + 1;
	d_chksbuf();

	sp->s_dimstr = NULL;
	sp->s_dtype = dtype;
	sp->s_flags = flags;

	return (sp);
}


/* D_LOOKUP -- Lookup a symbol in the symbol table.  Return a pointer to the
 * symbol table entry.
 */
struct symbol *
d_lookup (name)
char	*name;			/* symbol name			*/
{
	register struct	symbol *sp;
	register struct	symbol *top = &sym[nsym-1];

	for (sp=sym;  sp <= top;  sp++)
	    if (sp->s_name[0] == name[0])
		if (strcmp (sp->s_name, name) == 0)
		    return (sp);

	return (NULL);
}


/* D_CHKSBUF -- Check for overflow on the string buffer.
 */
void
d_chksbuf()
{
	if (nextch > SPMAX)
	    error (XPP_COMPERR, "decl string buffer overflow");
}


/* D_GETTOK -- Get the next token from the input stream.  Return the integer
 * value of the first character of the token as the function value.  EOF
 * is an error in this application, not a token.
 */
int
d_gettok (tokstr, maxch)
char	*tokstr;		/* receives token string	*/
int	maxch;			/* max chars to token string	*/
{
	register char 	*op = tokstr;
	register int	ch, n;



	/* Skip whitespace and comments to first char of next token.
	 */
	do {
	    ch = yy_input();
	} while (ch == ' ' || ch == '\t');

	if (ch == '#') {
	    /* Skip a comment.
	     */
	    while ((ch = yy_input()) != '\n' && ch > 0)
		;
	}

	if (ch <= 0)
	    error (XPP_SYNTAX, "unexpected EOF");

	*op++ = ch;
	n = maxch - 1;

	if (isalpha (ch)) {
	    /* Identifer.
	     */
	    while ((ch = yy_input()) > 0)
		if (isalnum(ch) || ch == '_') {
		    *op++ = ch;
		    if (--n <= 0)
			error (XPP_SYNTAX, "identifier too long");
		} else {
		    yy_unput (ch);
		    break;
		}

	} else if (isdigit (ch)) {
	    /* Number.
	     */
	    while ((ch = yy_input()) > 0)
		if (isdigit(ch)) {
		    *op++ = ch;
		    if (--n <= 0)
			error (XPP_SYNTAX, "number too long");
		} else {
		    yy_unput (ch);
		    break;
		}

	}

	*op++ = '\0';
	if (ch <= 0)
	    error (XPP_SYNTAX, "unexpected EOF");

	return (tokstr[0]);
}


/* D_DECLFUNC -- Declare a function.  This module is provided to allow
 * for any special treatment required for certain types of function
 * declarations.
 */
void
d_declfunc (sp, fp)
register struct symbol *sp;
FILE  *fp;
{
	d_makedecl (sp, fp);
}