xref: /csrg-svn/old/dbx/modula-2.c (revision 38105)
121613Sdist /*
2*38105Sbostic  * Copyright (c) 1983 The Regents of the University of California.
3*38105Sbostic  * All rights reserved.
4*38105Sbostic  *
5*38105Sbostic  * Redistribution and use in source and binary forms are permitted
6*38105Sbostic  * provided that the above copyright notice and this paragraph are
7*38105Sbostic  * duplicated in all such forms and that any documentation,
8*38105Sbostic  * advertising materials, and other materials related to such
9*38105Sbostic  * distribution and use acknowledge that the software was developed
10*38105Sbostic  * by the University of California, Berkeley.  The name of the
11*38105Sbostic  * University may not be used to endorse or promote products derived
12*38105Sbostic  * from this software without specific prior written permission.
13*38105Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*38105Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*38105Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621613Sdist  */
1718261Slinton 
1816622Ssam #ifndef lint
19*38105Sbostic static char sccsid[] = "@(#)modula-2.c	5.3 (Berkeley) 05/23/89";
20*38105Sbostic #endif /* not lint */
2116622Ssam 
2216622Ssam /*
2316622Ssam  * Modula-2 specific symbol routines.
2416622Ssam  */
2516622Ssam 
2616622Ssam #include "defs.h"
2716622Ssam #include "symbols.h"
2816622Ssam #include "modula-2.h"
2916622Ssam #include "languages.h"
3016622Ssam #include "tree.h"
3116622Ssam #include "eval.h"
3216622Ssam #include "mappings.h"
3316622Ssam #include "process.h"
3416622Ssam #include "runtime.h"
3516622Ssam #include "machine.h"
3616622Ssam 
3716622Ssam #ifndef public
3816622Ssam #endif
3916622Ssam 
4016622Ssam private Language mod2;
4116622Ssam private boolean initialized;
4216622Ssam 
4318261Slinton 
4418261Slinton #define ischar(t) ( \
4518261Slinton     (t) == t_char->type or \
4618261Slinton     ((t)->class == RANGE and istypename((t)->type, "char")) \
4718261Slinton )
4818261Slinton 
4916622Ssam /*
5016622Ssam  * Initialize Modula-2 information.
5116622Ssam  */
5216622Ssam 
5316622Ssam public modula2_init ()
5416622Ssam {
5516622Ssam     mod2 = language_define("modula-2", ".mod");
5616622Ssam     language_setop(mod2, L_PRINTDECL, modula2_printdecl);
5716622Ssam     language_setop(mod2, L_PRINTVAL, modula2_printval);
5816622Ssam     language_setop(mod2, L_TYPEMATCH, modula2_typematch);
5916622Ssam     language_setop(mod2, L_BUILDAREF, modula2_buildaref);
6016622Ssam     language_setop(mod2, L_EVALAREF, modula2_evalaref);
6116622Ssam     language_setop(mod2, L_MODINIT, modula2_modinit);
6216622Ssam     language_setop(mod2, L_HASMODULES, modula2_hasmodules);
6316622Ssam     language_setop(mod2, L_PASSADDR, modula2_passaddr);
6416622Ssam     initialized = false;
6516622Ssam }
6616622Ssam 
6716622Ssam /*
6816622Ssam  * Typematch tests if two types are compatible.  The issue
6916622Ssam  * is a bit complicated, so several subfunctions are used for
7016622Ssam  * various kinds of compatibility.
7116622Ssam  */
7216622Ssam 
7318261Slinton private boolean builtinmatch (t1, t2)
7418261Slinton register Symbol t1, t2;
7518261Slinton {
7618261Slinton     boolean b;
7718261Slinton 
7818261Slinton     b = (boolean) (
7918261Slinton 	(
8018261Slinton 	    t2 == t_int->type and t1->class == RANGE and
8118261Slinton 	    (
8218261Slinton 		istypename(t1->type, "integer") or
8318261Slinton 		istypename(t1->type, "cardinal")
8418261Slinton 	    )
8518261Slinton 	) or (
8618261Slinton 	    t2 == t_char->type and
8718261Slinton 	    t1->class == RANGE and istypename(t1->type, "char")
8818261Slinton 	) or (
8918261Slinton 	    t2 == t_real->type and
9018261Slinton 	    t1->class == RANGE and (
9118261Slinton 		istypename(t1->type, "real") or
9218261Slinton 		istypename(t1->type, "longreal")
9318261Slinton 	    )
9418261Slinton 	) or (
9518261Slinton 	    t2 == t_boolean->type and
9618261Slinton 	    t1->class == RANGE and istypename(t1->type, "boolean")
9718261Slinton 	)
9818261Slinton     );
9918261Slinton     return b;
10018261Slinton }
10118261Slinton 
10216622Ssam private boolean nilMatch (t1, t2)
10316622Ssam register Symbol t1, t2;
10416622Ssam {
10516622Ssam     boolean b;
10616622Ssam 
10716622Ssam     b = (boolean) (
10816622Ssam 	(t1 == t_nil and t2->class == PTR) or
10916622Ssam 	(t1->class == PTR and t2 == t_nil)
11016622Ssam     );
11116622Ssam     return b;
11216622Ssam }
11316622Ssam 
11416622Ssam private boolean enumMatch (t1, t2)
11516622Ssam register Symbol t1, t2;
11616622Ssam {
11716622Ssam     boolean b;
11816622Ssam 
11916622Ssam     b = (boolean) (
12018261Slinton 	(t1->class == SCAL and t2->class == CONST and t2->type == t1) or
12118261Slinton 	(t1->class == CONST and t2->class == SCAL and t1->type == t2)
12216622Ssam     );
12316622Ssam     return b;
12416622Ssam }
12516622Ssam 
12616622Ssam private boolean openArrayMatch (t1, t2)
12716622Ssam register Symbol t1, t2;
12816622Ssam {
12916622Ssam     boolean b;
13016622Ssam 
13116622Ssam     b = (boolean) (
13216622Ssam 	(
13333326Sdonn 	    t1->class == OPENARRAY and t1->symvalue.ndims == 1 and
13416622Ssam 	    t2->class == ARRAY and
13516622Ssam 	    compatible(rtype(t2->chain)->type, t_int) and
13616622Ssam 	    compatible(t1->type, t2->type)
13716622Ssam 	) or (
13833326Sdonn 	    t2->class == OPENARRAY and t2->symvalue.ndims == 1 and
13916622Ssam 	    t1->class == ARRAY and
14016622Ssam 	    compatible(rtype(t1->chain)->type, t_int) and
14116622Ssam 	    compatible(t1->type, t2->type)
14216622Ssam 	)
14316622Ssam     );
14416622Ssam     return b;
14516622Ssam }
14616622Ssam 
14716622Ssam private boolean isConstString (t)
14816622Ssam register Symbol t;
14916622Ssam {
15016622Ssam     boolean b;
15116622Ssam 
15216622Ssam     b = (boolean) (
15316622Ssam 	t->language == primlang and t->class == ARRAY and t->type == t_char
15416622Ssam     );
15516622Ssam     return b;
15616622Ssam }
15716622Ssam 
15816622Ssam private boolean stringArrayMatch (t1, t2)
15916622Ssam register Symbol t1, t2;
16016622Ssam {
16116622Ssam     boolean b;
16216622Ssam 
16316622Ssam     b = (boolean) (
16416622Ssam 	(
16516622Ssam 	    isConstString(t1) and
16616622Ssam 	    t2->class == ARRAY and compatible(t2->type, t_char->type)
16716622Ssam 	) or (
16816622Ssam 	    isConstString(t2) and
16916622Ssam 	    t1->class == ARRAY and compatible(t1->type, t_char->type)
17016622Ssam 	)
17116622Ssam     );
17216622Ssam     return b;
17316622Ssam }
17416622Ssam 
17516622Ssam public boolean modula2_typematch (type1, type2)
17616622Ssam Symbol type1, type2;
17716622Ssam {
17818261Slinton     boolean b;
17916622Ssam     Symbol t1, t2, tmp;
18016622Ssam 
18116622Ssam     t1 = rtype(type1);
18216622Ssam     t2 = rtype(type2);
18316622Ssam     if (t1 == t2) {
18416622Ssam 	b = true;
18516622Ssam     } else {
18618261Slinton 	if (t1 == t_char->type or t1 == t_int->type or
18718261Slinton 	    t1 == t_real->type or t1 == t_boolean->type
18818261Slinton 	) {
18916622Ssam 	    tmp = t1;
19016622Ssam 	    t1 = t2;
19116622Ssam 	    t2 = tmp;
19216622Ssam 	}
19316622Ssam 	b = (Boolean) (
19433326Sdonn 	    builtinmatch(t1, t2) or
19518261Slinton 	    nilMatch(t1, t2) or enumMatch(t1, t2) or
19618261Slinton 	    openArrayMatch(t1, t2) or stringArrayMatch(t1, t2)
19716622Ssam 	);
19816622Ssam     }
19916622Ssam     return b;
20016622Ssam }
20116622Ssam 
20216622Ssam /*
20316622Ssam  * Indent n spaces.
20416622Ssam  */
20516622Ssam 
20616622Ssam private indent (n)
20716622Ssam int n;
20816622Ssam {
20916622Ssam     if (n > 0) {
21016622Ssam 	printf("%*c", n, ' ');
21116622Ssam     }
21216622Ssam }
21316622Ssam 
21416622Ssam public modula2_printdecl (s)
21516622Ssam Symbol s;
21616622Ssam {
21716622Ssam     register Symbol t;
21816622Ssam     Boolean semicolon;
21916622Ssam 
22016622Ssam     semicolon = true;
22116622Ssam     if (s->class == TYPEREF) {
22216622Ssam 	resolveRef(t);
22316622Ssam     }
22416622Ssam     switch (s->class) {
22516622Ssam 	case CONST:
22616622Ssam 	    if (s->type->class == SCAL) {
22718261Slinton 		semicolon = false;
22818261Slinton 		printf("enumeration constant with value ");
22918261Slinton 		eval(s->symvalue.constval);
23018261Slinton 		modula2_printval(s);
23116622Ssam 	    } else {
23216622Ssam 		printf("const %s = ", symname(s));
23318261Slinton 		eval(s->symvalue.constval);
23416622Ssam 		modula2_printval(s);
23516622Ssam 	    }
23616622Ssam 	    break;
23716622Ssam 
23816622Ssam 	case TYPE:
23916622Ssam 	    printf("type %s = ", symname(s));
24016622Ssam 	    printtype(s, s->type, 0);
24116622Ssam 	    break;
24216622Ssam 
24316622Ssam 	case TYPEREF:
24416622Ssam 	    printf("type %s", symname(s));
24516622Ssam 	    break;
24616622Ssam 
24716622Ssam 	case VAR:
24816622Ssam 	    if (isparam(s)) {
24916622Ssam 		printf("(parameter) %s : ", symname(s));
25016622Ssam 	    } else {
25116622Ssam 		printf("var %s : ", symname(s));
25216622Ssam 	    }
25316622Ssam 	    printtype(s, s->type, 0);
25416622Ssam 	    break;
25516622Ssam 
25616622Ssam 	case REF:
25716622Ssam 	    printf("(var parameter) %s : ", symname(s));
25816622Ssam 	    printtype(s, s->type, 0);
25916622Ssam 	    break;
26016622Ssam 
26116622Ssam 	case RANGE:
26216622Ssam 	case ARRAY:
26333326Sdonn 	case OPENARRAY:
26418261Slinton 	case DYNARRAY:
26518261Slinton 	case SUBARRAY:
26616622Ssam 	case RECORD:
26716622Ssam 	case VARNT:
26816622Ssam 	case PTR:
26916622Ssam 	    printtype(s, s, 0);
27016622Ssam 	    semicolon = false;
27116622Ssam 	    break;
27216622Ssam 
27316622Ssam 	case FVAR:
27416622Ssam 	    printf("(function variable) %s : ", symname(s));
27516622Ssam 	    printtype(s, s->type, 0);
27616622Ssam 	    break;
27716622Ssam 
27816622Ssam 	case FIELD:
27916622Ssam 	    printf("(field) %s : ", symname(s));
28016622Ssam 	    printtype(s, s->type, 0);
28116622Ssam 	    break;
28216622Ssam 
28316622Ssam 	case PROC:
28416622Ssam 	    printf("procedure %s", symname(s));
28516622Ssam 	    listparams(s);
28616622Ssam 	    break;
28716622Ssam 
28816622Ssam 	case PROG:
28916622Ssam 	    printf("program %s", symname(s));
29016622Ssam 	    listparams(s);
29116622Ssam 	    break;
29216622Ssam 
29316622Ssam 	case FUNC:
29418261Slinton 	    printf("procedure %s", symname(s));
29516622Ssam 	    listparams(s);
29616622Ssam 	    printf(" : ");
29716622Ssam 	    printtype(s, s->type, 0);
29816622Ssam 	    break;
29916622Ssam 
30016622Ssam 	case MODULE:
30116622Ssam 	    printf("module %s", symname(s));
30216622Ssam 	    break;
30316622Ssam 
30416622Ssam 	default:
30518261Slinton 	    printf("[%s]", classname(s));
30616622Ssam 	    break;
30716622Ssam     }
30816622Ssam     if (semicolon) {
30916622Ssam 	putchar(';');
31016622Ssam     }
31116622Ssam     putchar('\n');
31216622Ssam }
31316622Ssam 
31416622Ssam /*
31516622Ssam  * Recursive whiz-bang procedure to print the type portion
31616622Ssam  * of a declaration.
31716622Ssam  *
31816622Ssam  * The symbol associated with the type is passed to allow
31916622Ssam  * searching for type names without getting "type blah = blah".
32016622Ssam  */
32116622Ssam 
32216622Ssam private printtype (s, t, n)
32316622Ssam Symbol s;
32416622Ssam Symbol t;
32516622Ssam int n;
32616622Ssam {
32718261Slinton     Symbol tmp;
32818261Slinton     int i;
32916622Ssam 
33016622Ssam     if (t->class == TYPEREF) {
33116622Ssam 	resolveRef(t);
33216622Ssam     }
33316622Ssam     switch (t->class) {
33416622Ssam 	case VAR:
33516622Ssam 	case CONST:
33616622Ssam 	case FUNC:
33716622Ssam 	case PROC:
33816622Ssam 	    panic("printtype: class %s", classname(t));
33916622Ssam 	    break;
34016622Ssam 
34116622Ssam 	case ARRAY:
34216622Ssam 	    printf("array[");
34316622Ssam 	    tmp = t->chain;
34416622Ssam 	    if (tmp != nil) {
34516622Ssam 		for (;;) {
34616622Ssam 		    printtype(tmp, tmp, n);
34716622Ssam 		    tmp = tmp->chain;
34816622Ssam 		    if (tmp == nil) {
34916622Ssam 			break;
35016622Ssam 		    }
35116622Ssam 		    printf(", ");
35216622Ssam 		}
35316622Ssam 	    }
35416622Ssam 	    printf("] of ");
35516622Ssam 	    printtype(t, t->type, n);
35616622Ssam 	    break;
35716622Ssam 
35833326Sdonn 	case OPENARRAY:
35933326Sdonn 	    printf("array of ");
36033326Sdonn 	    for (i = 1; i < t->symvalue.ndims; i++) {
36133326Sdonn 		printf("array of ");
36233326Sdonn 	    }
36333326Sdonn 	    printtype(t, t->type, n);
36433326Sdonn 	    break;
36533326Sdonn 
36618261Slinton 	case DYNARRAY:
36718261Slinton 	    printf("dynarray of ");
36818261Slinton 	    for (i = 1; i < t->symvalue.ndims; i++) {
36918261Slinton 		printf("array of ");
37018261Slinton 	    }
37118261Slinton 	    printtype(t, t->type, n);
37218261Slinton 	    break;
37318261Slinton 
37418261Slinton 	case SUBARRAY:
37518261Slinton 	    printf("subarray of ");
37618261Slinton 	    for (i = 1; i < t->symvalue.ndims; i++) {
37718261Slinton 		printf("array of ");
37818261Slinton 	    }
37918261Slinton 	    printtype(t, t->type, n);
38018261Slinton 	    break;
38118261Slinton 
38216622Ssam 	case RECORD:
38316622Ssam 	    printRecordDecl(t, n);
38416622Ssam 	    break;
38516622Ssam 
38616622Ssam 	case FIELD:
38716622Ssam 	    if (t->chain != nil) {
38816622Ssam 		printtype(t->chain, t->chain, n);
38916622Ssam 	    }
39016622Ssam 	    printf("\t%s : ", symname(t));
39116622Ssam 	    printtype(t, t->type, n);
39216622Ssam 	    printf(";\n");
39316622Ssam 	    break;
39416622Ssam 
39516622Ssam 	case RANGE:
39616622Ssam 	    printRangeDecl(t);
39716622Ssam 	    break;
39816622Ssam 
39916622Ssam 	case PTR:
40016622Ssam 	    printf("pointer to ");
40116622Ssam 	    printtype(t, t->type, n);
40216622Ssam 	    break;
40316622Ssam 
40416622Ssam 	case TYPE:
40516622Ssam 	    if (t->name != nil and ident(t->name)[0] != '\0') {
40616622Ssam 		printname(stdout, t);
40716622Ssam 	    } else {
40816622Ssam 		printtype(t, t->type, n);
40916622Ssam 	    }
41016622Ssam 	    break;
41116622Ssam 
41216622Ssam 	case SCAL:
41316622Ssam 	    printEnumDecl(t, n);
41416622Ssam 	    break;
41516622Ssam 
41616622Ssam 	case SET:
41716622Ssam 	    printf("set of ");
41816622Ssam 	    printtype(t, t->type, n);
41916622Ssam 	    break;
42016622Ssam 
42116622Ssam 	case TYPEREF:
42216622Ssam 	    break;
42316622Ssam 
42418261Slinton 	case FPROC:
42518261Slinton 	case FFUNC:
42618261Slinton 	    printf("procedure");
42718261Slinton 	    break;
42818261Slinton 
42916622Ssam 	default:
43018261Slinton 	    printf("[%s]", classname(t));
43116622Ssam 	    break;
43216622Ssam     }
43316622Ssam }
43416622Ssam 
43516622Ssam /*
43616622Ssam  * Print out a record declaration.
43716622Ssam  */
43816622Ssam 
43916622Ssam private printRecordDecl (t, n)
44016622Ssam Symbol t;
44116622Ssam int n;
44216622Ssam {
44316622Ssam     register Symbol f;
44416622Ssam 
44516622Ssam     if (t->chain == nil) {
44616622Ssam 	printf("record end");
44716622Ssam     } else {
44816622Ssam 	printf("record\n");
44916622Ssam 	for (f = t->chain; f != nil; f = f->chain) {
45016622Ssam 	    indent(n+4);
45116622Ssam 	    printf("%s : ", symname(f));
45216622Ssam 	    printtype(f->type, f->type, n+4);
45316622Ssam 	    printf(";\n");
45416622Ssam 	}
45516622Ssam 	indent(n);
45616622Ssam 	printf("end");
45716622Ssam     }
45816622Ssam }
45916622Ssam 
46016622Ssam /*
46116622Ssam  * Print out the declaration of a range type.
46216622Ssam  */
46316622Ssam 
46416622Ssam private printRangeDecl (t)
46516622Ssam Symbol t;
46616622Ssam {
46716622Ssam     long r0, r1;
46816622Ssam 
46916622Ssam     r0 = t->symvalue.rangev.lower;
47016622Ssam     r1 = t->symvalue.rangev.upper;
47118261Slinton     if (ischar(t)) {
47216622Ssam 	if (r0 < 0x20 or r0 > 0x7e) {
47316622Ssam 	    printf("%ld..", r0);
47416622Ssam 	} else {
47516622Ssam 	    printf("'%c'..", (char) r0);
47616622Ssam 	}
47716622Ssam 	if (r1 < 0x20 or r1 > 0x7e) {
47816622Ssam 	    printf("\\%lo", r1);
47916622Ssam 	} else {
48016622Ssam 	    printf("'%c'", (char) r1);
48116622Ssam 	}
48216622Ssam     } else if (r0 > 0 and r1 == 0) {
48316622Ssam 	printf("%ld byte real", r0);
48416622Ssam     } else if (r0 >= 0) {
48516622Ssam 	printf("%lu..%lu", r0, r1);
48616622Ssam     } else {
48716622Ssam 	printf("%ld..%ld", r0, r1);
48816622Ssam     }
48916622Ssam }
49016622Ssam 
49116622Ssam /*
49216622Ssam  * Print out an enumeration declaration.
49316622Ssam  */
49416622Ssam 
49516622Ssam private printEnumDecl (e, n)
49616622Ssam Symbol e;
49716622Ssam int n;
49816622Ssam {
49916622Ssam     Symbol t;
50016622Ssam 
50116622Ssam     printf("(");
50216622Ssam     t = e->chain;
50316622Ssam     if (t != nil) {
50416622Ssam 	printf("%s", symname(t));
50516622Ssam 	t = t->chain;
50616622Ssam 	while (t != nil) {
50716622Ssam 	    printf(", %s", symname(t));
50816622Ssam 	    t = t->chain;
50916622Ssam 	}
51016622Ssam     }
51116622Ssam     printf(")");
51216622Ssam }
51316622Ssam 
51416622Ssam /*
51516622Ssam  * List the parameters of a procedure or function.
51616622Ssam  * No attempt is made to combine like types.
51716622Ssam  */
51816622Ssam 
51916622Ssam private listparams (s)
52016622Ssam Symbol s;
52116622Ssam {
52216622Ssam     Symbol t;
52316622Ssam 
52416622Ssam     if (s->chain != nil) {
52516622Ssam 	putchar('(');
52616622Ssam 	for (t = s->chain; t != nil; t = t->chain) {
52716622Ssam 	    switch (t->class) {
52816622Ssam 		case REF:
52916622Ssam 		    printf("var ");
53016622Ssam 		    break;
53116622Ssam 
53216622Ssam 		case FPROC:
53316622Ssam 		case FFUNC:
53416622Ssam 		    printf("procedure ");
53516622Ssam 		    break;
53616622Ssam 
53716622Ssam 		case VAR:
53816622Ssam 		    break;
53916622Ssam 
54016622Ssam 		default:
54116622Ssam 		    panic("unexpected class %d for parameter", t->class);
54216622Ssam 	    }
54316622Ssam 	    printf("%s", symname(t));
54416622Ssam 	    if (s->class == PROG) {
54516622Ssam 		printf(", ");
54616622Ssam 	    } else {
54716622Ssam 		printf(" : ");
54816622Ssam 		printtype(t, t->type, 0);
54916622Ssam 		if (t->chain != nil) {
55016622Ssam 		    printf("; ");
55116622Ssam 		}
55216622Ssam 	    }
55316622Ssam 	}
55416622Ssam 	putchar(')');
55516622Ssam     }
55616622Ssam }
55716622Ssam 
55816622Ssam /*
55918261Slinton  * Test if a pointer type should be treated as a null-terminated string.
56018261Slinton  * The type given is the type that is pointed to.
56118261Slinton  */
56218261Slinton 
56318261Slinton private boolean isCstring (type)
56418261Slinton Symbol type;
56518261Slinton {
56618261Slinton     boolean b;
56718261Slinton     register Symbol a, t;
56818261Slinton 
56918261Slinton     a = rtype(type);
57018261Slinton     if (a->class == ARRAY) {
57118261Slinton 	t = rtype(a->chain);
57218261Slinton 	b = (boolean) (
57318261Slinton 	    t->class == RANGE and istypename(a->type, "char") and
57418261Slinton 	    (t->symvalue.rangev.upper - t->symvalue.rangev.lower + 1) <= 0
57518261Slinton 	);
57618261Slinton     } else {
57718261Slinton 	b = false;
57818261Slinton     }
57918261Slinton     return b;
58018261Slinton }
58118261Slinton 
58218261Slinton /*
58316622Ssam  * Modula 2 interface to printval.
58416622Ssam  */
58516622Ssam 
58616622Ssam public modula2_printval (s)
58716622Ssam Symbol s;
58816622Ssam {
58916622Ssam     prval(s, size(s));
59016622Ssam }
59116622Ssam 
59216622Ssam /*
59316622Ssam  * Print out the value on the top of the expression stack
59416622Ssam  * in the format for the type of the given symbol, assuming
59516622Ssam  * the size of the object is n bytes.
59616622Ssam  */
59716622Ssam 
59816622Ssam private prval (s, n)
59916622Ssam Symbol s;
60016622Ssam integer n;
60116622Ssam {
60216622Ssam     Symbol t;
60316622Ssam     Address a;
60416622Ssam     integer len;
60516622Ssam     double r;
60618261Slinton     integer i;
60716622Ssam 
60816622Ssam     if (s->class == TYPEREF) {
60916622Ssam 	resolveRef(s);
61016622Ssam     }
61116622Ssam     switch (s->class) {
61216622Ssam 	case CONST:
61316622Ssam 	case TYPE:
61418261Slinton 	case REF:
61516622Ssam 	case VAR:
61616622Ssam 	case FVAR:
61716622Ssam 	case TAG:
61816622Ssam 	    prval(s->type, n);
61916622Ssam 	    break;
62016622Ssam 
62118261Slinton 	case FIELD:
62218261Slinton 	    if (isbitfield(s)) {
62333326Sdonn 		i = extractField(s);
62418261Slinton 		t = rtype(s->type);
62518261Slinton 		if (t->class == SCAL) {
62618261Slinton 		    printEnum(i, t);
62718261Slinton 		} else {
62818261Slinton 		    printRangeVal(i, t);
62918261Slinton 		}
63018261Slinton 	    } else {
63118261Slinton 		prval(s->type, n);
63218261Slinton 	    }
63318261Slinton 	    break;
63418261Slinton 
63516622Ssam 	case ARRAY:
63616622Ssam 	    t = rtype(s->type);
63718261Slinton 	    if (ischar(t)) {
63816622Ssam 		len = size(s);
63916622Ssam 		sp -= len;
64018261Slinton 		printf("\"%.*s\"", len, sp);
64116622Ssam 		break;
64216622Ssam 	    } else {
64316622Ssam 		printarray(s);
64416622Ssam 	    }
64516622Ssam 	    break;
64616622Ssam 
64733326Sdonn 	case OPENARRAY:
64818261Slinton 	case DYNARRAY:
64918261Slinton 	    printDynarray(s);
65018261Slinton 	    break;
65118261Slinton 
65218261Slinton 	case SUBARRAY:
65318261Slinton 	    printSubarray(s);
65418261Slinton 	    break;
65518261Slinton 
65616622Ssam 	case RECORD:
65716622Ssam 	    printrecord(s);
65816622Ssam 	    break;
65916622Ssam 
66016622Ssam 	case VARNT:
66118261Slinton 	    printf("[variant]");
66216622Ssam 	    break;
66316622Ssam 
66416622Ssam 	case RANGE:
66516622Ssam 	    printrange(s, n);
66616622Ssam 	    break;
66716622Ssam 
66818261Slinton 	/*
66918261Slinton 	 * Unresolved opaque type.
67018261Slinton 	 * Probably a pointer.
67118261Slinton 	 */
67218261Slinton 	case TYPEREF:
67318261Slinton 	    a = pop(Address);
67418261Slinton 	    printf("@%x", a);
67518261Slinton 	    break;
67618261Slinton 
67716622Ssam 	case FILET:
67818261Slinton 	    a = pop(Address);
67918261Slinton 	    if (a == 0) {
68018261Slinton 		printf("nil");
68118261Slinton 	    } else {
68218261Slinton 		printf("0x%x", a);
68318261Slinton 	    }
68418261Slinton 	    break;
68518261Slinton 
68616622Ssam 	case PTR:
68716622Ssam 	    a = pop(Address);
68816622Ssam 	    if (a == 0) {
68916622Ssam 		printf("nil");
69018261Slinton 	    } else if (isCstring(s->type)) {
69118261Slinton 		printString(a, true);
69216622Ssam 	    } else {
69316622Ssam 		printf("0x%x", a);
69416622Ssam 	    }
69516622Ssam 	    break;
69616622Ssam 
69716622Ssam 	case SCAL:
69818261Slinton 	    i = 0;
69918261Slinton 	    popn(n, &i);
70018261Slinton 	    printEnum(i, s);
70116622Ssam 	    break;
70216622Ssam 
70316622Ssam 	case FPROC:
70416622Ssam 	case FFUNC:
70516622Ssam 	    a = pop(long);
70616622Ssam 	    t = whatblock(a);
70716622Ssam 	    if (t == nil) {
70818261Slinton 		printf("0x%x", a);
70916622Ssam 	    } else {
71018261Slinton 		printname(stdout, t);
71116622Ssam 	    }
71216622Ssam 	    break;
71316622Ssam 
71416622Ssam 	case SET:
71516622Ssam 	    printSet(s);
71616622Ssam 	    break;
71716622Ssam 
71816622Ssam 	default:
71916622Ssam 	    if (ord(s->class) < ord(BADUSE) or ord(s->class) > ord(TYPEREF)) {
72016622Ssam 		panic("printval: bad class %d", ord(s->class));
72116622Ssam 	    }
72216622Ssam 	    printf("[%s]", classname(s));
72316622Ssam 	    break;
72416622Ssam     }
72516622Ssam }
72616622Ssam 
72716622Ssam /*
72818261Slinton  * Print out a dynamic array.
72918261Slinton  */
73018261Slinton 
73118261Slinton private Address printDynSlice();
73218261Slinton 
73318261Slinton private printDynarray (t)
73418261Slinton Symbol t;
73518261Slinton {
73618261Slinton     Address base;
73718261Slinton     integer n;
73818261Slinton     Stack *savesp, *newsp;
73918261Slinton     Symbol eltype;
74018261Slinton 
74118261Slinton     savesp = sp;
74218261Slinton     sp -= (t->symvalue.ndims * sizeof(Word));
74318261Slinton     base = pop(Address);
74418261Slinton     newsp = sp;
74518261Slinton     sp = savesp;
74618261Slinton     eltype = rtype(t->type);
74718261Slinton     if (t->symvalue.ndims == 0) {
74818261Slinton 	if (ischar(eltype)) {
74918261Slinton 	    printString(base, true);
75018261Slinton 	} else {
75118261Slinton 	    printf("[dynarray @nocount]");
75218261Slinton 	}
75318261Slinton     } else {
75418261Slinton 	n = ((long *) sp)[-(t->symvalue.ndims)];
75518261Slinton 	base = printDynSlice(base, n, t->symvalue.ndims, eltype, size(eltype));
75618261Slinton     }
75718261Slinton     sp = newsp;
75818261Slinton }
75918261Slinton 
76018261Slinton /*
76118261Slinton  * Print out one dimension of a multi-dimension dynamic array.
76218261Slinton  *
76318261Slinton  * Return the address of the element that follows the printed elements.
76418261Slinton  */
76518261Slinton 
76618261Slinton private Address printDynSlice (base, count, ndims, eltype, elsize)
76718261Slinton Address base;
76818261Slinton integer count, ndims;
76918261Slinton Symbol eltype;
77018261Slinton integer elsize;
77118261Slinton {
77218261Slinton     Address b;
77318261Slinton     integer i, n;
77418261Slinton     char *slice;
77518261Slinton     Stack *savesp;
77618261Slinton 
77718261Slinton     b = base;
77818261Slinton     if (ndims > 1) {
77918261Slinton 	n = ((long *) sp)[-ndims + 1];
78018261Slinton     }
78118261Slinton     if (ndims == 1 and ischar(eltype)) {
78218261Slinton 	slice = newarr(char, count);
78318261Slinton 	dread(slice, b, count);
78418261Slinton 	printf("\"%.*s\"", count, slice);
78518261Slinton 	dispose(slice);
78618261Slinton 	b += count;
78718261Slinton     } else {
78818261Slinton 	printf("(");
78918261Slinton 	for (i = 0; i < count; i++) {
79018261Slinton 	    if (i != 0) {
79118261Slinton 		printf(", ");
79218261Slinton 	    }
79318261Slinton 	    if (ndims == 1) {
79418261Slinton 		slice = newarr(char, elsize);
79518261Slinton 		dread(slice, b, elsize);
79618261Slinton 		savesp = sp;
79718261Slinton 		sp = slice + elsize;
79818261Slinton 		printval(eltype);
79918261Slinton 		sp = savesp;
80018261Slinton 		dispose(slice);
80118261Slinton 		b += elsize;
80218261Slinton 	    } else {
80318261Slinton 		b = printDynSlice(b, n, ndims - 1, eltype, elsize);
80418261Slinton 	    }
80518261Slinton 	}
80618261Slinton 	printf(")");
80718261Slinton     }
80818261Slinton     return b;
80918261Slinton }
81018261Slinton 
81118261Slinton private printSubarray (t)
81218261Slinton Symbol t;
81318261Slinton {
81418261Slinton     printf("[subarray]");
81518261Slinton }
81618261Slinton 
81718261Slinton /*
81816622Ssam  * Print out the value of a scalar (non-enumeration) type.
81916622Ssam  */
82016622Ssam 
82116622Ssam private printrange (s, n)
82216622Ssam Symbol s;
82316622Ssam integer n;
82416622Ssam {
82516622Ssam     double d;
82616622Ssam     float f;
82716622Ssam     integer i;
82816622Ssam 
82916622Ssam     if (s->symvalue.rangev.upper == 0 and s->symvalue.rangev.lower > 0) {
83016622Ssam 	if (n == sizeof(float)) {
83116622Ssam 	    popn(n, &f);
83216622Ssam 	    d = f;
83316622Ssam 	} else {
83416622Ssam 	    popn(n, &d);
83516622Ssam 	}
83616622Ssam 	prtreal(d);
83716622Ssam     } else {
83816622Ssam 	i = 0;
83916622Ssam 	popn(n, &i);
84018261Slinton 	printRangeVal(i, s);
84116622Ssam     }
84216622Ssam }
84316622Ssam 
84416622Ssam /*
84516622Ssam  * Print out a set.
84616622Ssam  */
84716622Ssam 
84816622Ssam private printSet (s)
84916622Ssam Symbol s;
85016622Ssam {
85116622Ssam     Symbol t;
85216622Ssam     integer nbytes;
85316622Ssam 
85416622Ssam     nbytes = size(s);
85516622Ssam     t = rtype(s->type);
85616622Ssam     printf("{");
85716622Ssam     sp -= nbytes;
85816622Ssam     if (t->class == SCAL) {
85916622Ssam 	printSetOfEnum(t);
86016622Ssam     } else if (t->class == RANGE) {
86116622Ssam 	printSetOfRange(t);
86216622Ssam     } else {
86316622Ssam 	panic("expected range or enumerated base type for set");
86416622Ssam     }
86516622Ssam     printf("}");
86616622Ssam }
86716622Ssam 
86816622Ssam /*
86916622Ssam  * Print out a set of an enumeration.
87016622Ssam  */
87116622Ssam 
87216622Ssam private printSetOfEnum (t)
87316622Ssam Symbol t;
87416622Ssam {
87516622Ssam     register Symbol e;
87616622Ssam     register integer i, j, *p;
87716622Ssam     boolean first;
87816622Ssam 
87916622Ssam     p = (int *) sp;
88016622Ssam     i = *p;
88116622Ssam     j = 0;
88216622Ssam     e = t->chain;
88316622Ssam     first = true;
88416622Ssam     while (e != nil) {
88516622Ssam 	if ((i&1) == 1) {
88616622Ssam 	    if (first) {
88716622Ssam 		first = false;
88816622Ssam 		printf("%s", symname(e));
88916622Ssam 	    } else {
89016622Ssam 		printf(", %s", symname(e));
89116622Ssam 	    }
89216622Ssam 	}
89316622Ssam 	i >>= 1;
89416622Ssam 	++j;
89516622Ssam 	if (j >= sizeof(integer)*BITSPERBYTE) {
89616622Ssam 	    j = 0;
89716622Ssam 	    ++p;
89816622Ssam 	    i = *p;
89916622Ssam 	}
90016622Ssam 	e = e->chain;
90116622Ssam     }
90216622Ssam }
90316622Ssam 
90416622Ssam /*
90516622Ssam  * Print out a set of a subrange type.
90616622Ssam  */
90716622Ssam 
90816622Ssam private printSetOfRange (t)
90916622Ssam Symbol t;
91016622Ssam {
91116622Ssam     register integer i, j, *p;
91216622Ssam     long v;
91316622Ssam     boolean first;
91416622Ssam 
91516622Ssam     p = (int *) sp;
91616622Ssam     i = *p;
91716622Ssam     j = 0;
91816622Ssam     v = t->symvalue.rangev.lower;
91916622Ssam     first = true;
92016622Ssam     while (v <= t->symvalue.rangev.upper) {
92116622Ssam 	if ((i&1) == 1) {
92216622Ssam 	    if (first) {
92316622Ssam 		first = false;
92416622Ssam 		printf("%ld", v);
92516622Ssam 	    } else {
92616622Ssam 		printf(", %ld", v);
92716622Ssam 	    }
92816622Ssam 	}
92916622Ssam 	i >>= 1;
93016622Ssam 	++j;
93116622Ssam 	if (j >= sizeof(integer)*BITSPERBYTE) {
93216622Ssam 	    j = 0;
93316622Ssam 	    ++p;
93416622Ssam 	    i = *p;
93516622Ssam 	}
93616622Ssam 	++v;
93716622Ssam     }
93816622Ssam }
93916622Ssam 
94016622Ssam /*
94118261Slinton  * Construct a node for subscripting a dynamic or subarray.
94218261Slinton  * The list of indices is left for processing in evalaref,
94318261Slinton  * unlike normal subscripting in which the list is expanded
94418261Slinton  * across individual INDEX nodes.
94518261Slinton  */
94618261Slinton 
94718261Slinton private Node dynref (a, t, slist)
94818261Slinton Node a;
94918261Slinton Symbol t;
95018261Slinton Node slist;
95118261Slinton {
95218261Slinton     Node p, r;
95318261Slinton     integer n;
95418261Slinton 
95518261Slinton     p = slist;
95618261Slinton     n = 0;
95718261Slinton     while (p != nil) {
95818261Slinton 	if (not compatible(p->value.arg[0]->nodetype, t_int)) {
95918261Slinton 	    suberror("subscript \"", p->value.arg[0], "\" is the wrong type");
96018261Slinton 	}
96118261Slinton 	++n;
96218261Slinton 	p = p->value.arg[1];
96318261Slinton     }
96418261Slinton     if (n > t->symvalue.ndims and (t->symvalue.ndims != 0 or n != 1)) {
96518261Slinton 	suberror("too many subscripts for ", a, nil);
96618261Slinton     } else if (n < t->symvalue.ndims) {
96718261Slinton 	suberror("not enough subscripts for ", a, nil);
96818261Slinton     }
96918261Slinton     r = build(O_INDEX, a, slist);
97018261Slinton     r->nodetype = rtype(t->type);
97118261Slinton     return r;
97218261Slinton }
97318261Slinton 
97418261Slinton /*
97516622Ssam  * Construct a node for subscripting.
97616622Ssam  */
97716622Ssam 
97816622Ssam public Node modula2_buildaref (a, slist)
97916622Ssam Node a, slist;
98016622Ssam {
98116622Ssam     register Symbol t;
98216622Ssam     register Node p;
98318261Slinton     Symbol eltype;
98416622Ssam     Node esub, r;
98518261Slinton     integer n;
98616622Ssam 
98716622Ssam     t = rtype(a->nodetype);
98833326Sdonn     switch (t->class) {
98933326Sdonn 	case OPENARRAY:
99033326Sdonn 	case DYNARRAY:
99133326Sdonn 	case SUBARRAY:
99233326Sdonn 	    r = dynref(a, t, slist);
99333326Sdonn 	    break;
99433326Sdonn 
99533326Sdonn 	case ARRAY:
99633326Sdonn 	    r = a;
99733326Sdonn 	    eltype = rtype(t->type);
99833326Sdonn 	    p = slist;
99933326Sdonn 	    t = t->chain;
100033326Sdonn 	    while (p != nil and t != nil) {
100133326Sdonn 		esub = p->value.arg[0];
100233326Sdonn 		if (not compatible(rtype(t), rtype(esub->nodetype))) {
100333326Sdonn 		    suberror("subscript \"", esub, "\" is the wrong type");
100433326Sdonn 		}
100533326Sdonn 		r = build(O_INDEX, r, esub);
100633326Sdonn 		r->nodetype = eltype;
100733326Sdonn 		p = p->value.arg[1];
100833326Sdonn 		t = t->chain;
100916622Ssam 	    }
101033326Sdonn 	    if (p != nil) {
101133326Sdonn 		suberror("too many subscripts for ", a, nil);
101233326Sdonn 	    } else if (t != nil) {
101333326Sdonn 		suberror("not enough subscripts for ", a, nil);
101433326Sdonn 	    }
101533326Sdonn 	    break;
101633326Sdonn 
101733326Sdonn 	default:
101833326Sdonn 	    suberror("\"", a, "\" is not an array");
101933326Sdonn 	    break;
102016622Ssam     }
102116622Ssam     return r;
102216622Ssam }
102316622Ssam 
102416622Ssam /*
102518261Slinton  * Subscript usage error reporting.
102618261Slinton  */
102718261Slinton 
102818261Slinton private suberror (s1, e1, s2)
102918261Slinton String s1, s2;
103018261Slinton Node e1;
103118261Slinton {
103218261Slinton     beginerrmsg();
103318261Slinton     if (s1 != nil) {
103418261Slinton 	fprintf(stderr, s1);
103518261Slinton     }
103618261Slinton     if (e1 != nil) {
103718261Slinton 	prtree(stderr, e1);
103818261Slinton     }
103918261Slinton     if (s2 != nil) {
104018261Slinton 	fprintf(stderr, s2);
104118261Slinton     }
104218261Slinton     enderrmsg();
104318261Slinton }
104418261Slinton 
104518261Slinton /*
104618261Slinton  * Check that a subscript value is in the appropriate range.
104718261Slinton  */
104818261Slinton 
104918261Slinton private subchk (value, lower, upper)
105018261Slinton long value, lower, upper;
105118261Slinton {
105218261Slinton     if (value < lower or value > upper) {
105318261Slinton 	error("subscript value %d out of range [%d..%d]", value, lower, upper);
105418261Slinton     }
105518261Slinton }
105618261Slinton 
105718261Slinton /*
105818261Slinton  * Compute the offset for subscripting a dynamic array.
105918261Slinton  */
106018261Slinton 
106118261Slinton private getdynoff (ndims, sub)
106218261Slinton integer ndims;
106318261Slinton long *sub;
106418261Slinton {
106518261Slinton     long k, off, *count;
106618261Slinton 
106718261Slinton     count = (long *) sp;
106818261Slinton     off = 0;
106918261Slinton     for (k = 0; k < ndims - 1; k++) {
107018261Slinton 	subchk(sub[k], 0, count[k] - 1);
107118261Slinton 	off += (sub[k] * count[k+1]);
107218261Slinton     }
107318261Slinton     subchk(sub[ndims - 1], 0, count[ndims - 1] - 1);
107418261Slinton     return off + sub[ndims - 1];
107518261Slinton }
107618261Slinton 
107718261Slinton /*
107818261Slinton  * Compute the offset associated with a subarray.
107918261Slinton  */
108018261Slinton 
108118261Slinton private getsuboff (ndims, sub)
108218261Slinton integer ndims;
108318261Slinton long *sub;
108418261Slinton {
108518261Slinton     long k, off;
108618261Slinton     struct subarrayinfo {
108718261Slinton 	long count;
108818261Slinton 	long mult;
108918261Slinton     } *info;
109018261Slinton 
109118261Slinton     info = (struct subarrayinfo *) sp;
109218261Slinton     off = 0;
109318261Slinton     for (k = 0; k < ndims; k++) {
109418261Slinton 	subchk(sub[k], 0, info[k].count - 1);
109518261Slinton 	off += sub[k] * info[k].mult;
109618261Slinton     }
109718261Slinton     return off;
109818261Slinton }
109918261Slinton 
110018261Slinton /*
110116622Ssam  * Evaluate a subscript index.
110216622Ssam  */
110316622Ssam 
110418261Slinton public modula2_evalaref (s, base, i)
110516622Ssam Symbol s;
110618261Slinton Address base;
110716622Ssam long i;
110816622Ssam {
110918261Slinton     Symbol t;
111018261Slinton     long lb, ub, off;
111118261Slinton     long *sub;
111218261Slinton     Address b;
111316622Ssam 
111418261Slinton     t = rtype(s);
111518261Slinton     if (t->class == ARRAY) {
111618261Slinton 	findbounds(rtype(t->chain), &lb, &ub);
111718261Slinton 	if (i < lb or i > ub) {
111818261Slinton 	    error("subscript %d out of range [%d..%d]", i, lb, ub);
111918261Slinton 	}
112018261Slinton 	push(long, base + (i - lb) * size(t->type));
112133326Sdonn     } else if ((t->class == OPENARRAY or t->class == DYNARRAY) and
112233326Sdonn 	t->symvalue.ndims == 0
112333326Sdonn     ) {
112418261Slinton 	push(long, base + i * size(t->type));
112533326Sdonn     } else if (t->class == OPENARRAY or t->class == DYNARRAY or
112633326Sdonn 	t->class == SUBARRAY
112733326Sdonn     ) {
112818261Slinton 	push(long, i);
112918261Slinton 	sub = (long *) (sp - (t->symvalue.ndims * sizeof(long)));
113018261Slinton 	rpush(base, size(t));
113118261Slinton 	sp -= (t->symvalue.ndims * sizeof(long));
113218261Slinton 	b = pop(Address);
113318261Slinton 	sp += sizeof(Address);
113418261Slinton 	if (t->class == SUBARRAY) {
113518261Slinton 	    off = getsuboff(t->symvalue.ndims, sub);
113618261Slinton 	} else {
113718261Slinton 	    off = getdynoff(t->symvalue.ndims, sub);
113818261Slinton 	}
113918261Slinton 	sp = (Stack *) sub;
114018261Slinton 	push(long, b + off * size(t->type));
114118261Slinton     } else {
114218261Slinton 	error("[internal error: expected array in evalaref]");
114316622Ssam     }
114416622Ssam }
114516622Ssam 
114616622Ssam /*
114716622Ssam  * Initial Modula-2 type information.
114816622Ssam  */
114916622Ssam 
115016622Ssam #define NTYPES 12
115116622Ssam 
115216622Ssam private Symbol inittype[NTYPES + 1];
115316622Ssam 
115416622Ssam private addType (n, s, lower, upper)
115516622Ssam integer n;
115616622Ssam String s;
115716622Ssam long lower, upper;
115816622Ssam {
115916622Ssam     register Symbol t;
116016622Ssam 
116116622Ssam     if (n > NTYPES) {
116216622Ssam 	panic("initial Modula-2 type number too large for '%s'", s);
116316622Ssam     }
116416622Ssam     t = insert(identname(s, true));
116516622Ssam     t->language = mod2;
116616622Ssam     t->class = TYPE;
116716622Ssam     t->type = newSymbol(nil, 0, RANGE, t, nil);
116816622Ssam     t->type->symvalue.rangev.lower = lower;
116916622Ssam     t->type->symvalue.rangev.upper = upper;
117016622Ssam     t->type->language = mod2;
117116622Ssam     inittype[n] = t;
117216622Ssam }
117316622Ssam 
117416622Ssam private initModTypes ()
117516622Ssam {
117616622Ssam     addType(1, "integer", 0x80000000L, 0x7fffffffL);
117716622Ssam     addType(2, "char", 0L, 255L);
117816622Ssam     addType(3, "boolean", 0L, 1L);
117916622Ssam     addType(4, "unsigned", 0L, 0xffffffffL);
118016622Ssam     addType(5, "real", 4L, 0L);
118116622Ssam     addType(6, "longreal", 8L, 0L);
118216622Ssam     addType(7, "word", 0L, 0xffffffffL);
118316622Ssam     addType(8, "byte", 0L, 255L);
118416622Ssam     addType(9, "address", 0L, 0xffffffffL);
118516622Ssam     addType(10, "file", 0L, 0xffffffffL);
118616622Ssam     addType(11, "process", 0L, 0xffffffffL);
118716622Ssam     addType(12, "cardinal", 0L, 0x7fffffffL);
118816622Ssam }
118916622Ssam 
119016622Ssam /*
119116622Ssam  * Initialize typetable.
119216622Ssam  */
119316622Ssam 
119416622Ssam public modula2_modinit (typetable)
119516622Ssam Symbol typetable[];
119616622Ssam {
119716622Ssam     register integer i;
119816622Ssam 
119916622Ssam     if (not initialized) {
120016622Ssam 	initModTypes();
120118261Slinton 	initialized = true;
120216622Ssam     }
120316622Ssam     for (i = 1; i <= NTYPES; i++) {
120416622Ssam 	typetable[i] = inittype[i];
120516622Ssam     }
120616622Ssam }
120716622Ssam 
120816622Ssam public boolean modula2_hasmodules ()
120916622Ssam {
121016622Ssam     return true;
121116622Ssam }
121216622Ssam 
121316622Ssam public boolean modula2_passaddr (param, exprtype)
121416622Ssam Symbol param, exprtype;
121516622Ssam {
121616622Ssam     return false;
121716622Ssam }
1218