Added .globl, fix in Xfit call
This commit is contained in:
62
lang/m2/comp/.distr
Normal file
62
lang/m2/comp/.distr
Normal file
@@ -0,0 +1,62 @@
|
||||
LLlex.c
|
||||
LLlex.h
|
||||
LLmessage.c
|
||||
Makefile
|
||||
Parameters
|
||||
Resolve
|
||||
SYSTEM.h
|
||||
Version.c
|
||||
casestat.C
|
||||
char.tab
|
||||
chk_expr.c
|
||||
chk_expr.h
|
||||
class.h
|
||||
code.c
|
||||
const.h
|
||||
cstoper.c
|
||||
debug.h
|
||||
declar.g
|
||||
def.H
|
||||
def.c
|
||||
defmodule.c
|
||||
desig.c
|
||||
desig.H
|
||||
em_m2.6
|
||||
enter.c
|
||||
error.c
|
||||
expression.g
|
||||
f_info.h
|
||||
idf.c
|
||||
idf.h
|
||||
input.c
|
||||
input.h
|
||||
lookup.c
|
||||
main.c
|
||||
main.h
|
||||
make.allocd
|
||||
make.hfiles
|
||||
make.next
|
||||
make.tokcase
|
||||
make.tokfile
|
||||
misc.c
|
||||
misc.h
|
||||
modula-2.1
|
||||
nmclash.c
|
||||
node.H
|
||||
node.c
|
||||
options.c
|
||||
program.g
|
||||
scope.C
|
||||
scope.h
|
||||
standards.h
|
||||
statement.g
|
||||
tab.c
|
||||
tmpvar.C
|
||||
tokenname.c
|
||||
tokenname.h
|
||||
type.H
|
||||
type.c
|
||||
typequiv.c
|
||||
walk.c
|
||||
walk.h
|
||||
warning.h
|
||||
580
lang/m2/comp/LLlex.c
Normal file
580
lang/m2/comp/LLlex.c
Normal file
@@ -0,0 +1,580 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* L E X I C A L A N A L Y S E R F O R M O D U L A - 2 */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "debug.h"
|
||||
#include "idfsize.h"
|
||||
#include "numsize.h"
|
||||
#include "strsize.h"
|
||||
|
||||
#include <alloc.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "LLlex.h"
|
||||
#include "input.h"
|
||||
#include "f_info.h"
|
||||
#include "Lpars.h"
|
||||
#include "class.h"
|
||||
#include "idf.h"
|
||||
#include "def.h"
|
||||
#include "type.h"
|
||||
#include "const.h"
|
||||
#include "warning.h"
|
||||
|
||||
long str2long();
|
||||
|
||||
struct token dot,
|
||||
aside;
|
||||
struct type *toktype;
|
||||
int idfsize = IDFSIZE;
|
||||
int ForeignFlag;
|
||||
#ifdef DEBUG
|
||||
extern int cntlines;
|
||||
#endif
|
||||
|
||||
static int eofseen;
|
||||
extern char options[];
|
||||
|
||||
STATIC
|
||||
SkipComment()
|
||||
{
|
||||
/* Skip Modula-2 comments (* ... *).
|
||||
Note that comments may be nested (par. 3.5).
|
||||
*/
|
||||
register int ch;
|
||||
register int CommentLevel = 0;
|
||||
|
||||
LoadChar(ch);
|
||||
if (ch == '$') {
|
||||
LoadChar(ch);
|
||||
switch(ch) {
|
||||
case 'F':
|
||||
/* Foreign; This definition module has an
|
||||
implementation in another language.
|
||||
In this case, don't generate prefixes in front
|
||||
of the names. Also, don't generate call to
|
||||
initialization routine.
|
||||
*/
|
||||
ForeignFlag = D_FOREIGN;
|
||||
break;
|
||||
case 'R':
|
||||
/* Range checks, on or off */
|
||||
LoadChar(ch);
|
||||
if (ch == '-') {
|
||||
options['R'] = 1;
|
||||
break;
|
||||
}
|
||||
if (ch == '+') {
|
||||
options['R'] = 0;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
PushBack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
if (class(ch) == STNL) {
|
||||
LineNumber++;
|
||||
#ifdef DEBUG
|
||||
cntlines++;
|
||||
#endif
|
||||
}
|
||||
else if (ch == '(') {
|
||||
LoadChar(ch);
|
||||
if (ch == '*') CommentLevel++;
|
||||
else continue;
|
||||
}
|
||||
else if (ch == '*') {
|
||||
LoadChar(ch);
|
||||
if (ch == ')') {
|
||||
CommentLevel--;
|
||||
if (CommentLevel < 0) break;
|
||||
}
|
||||
else continue;
|
||||
}
|
||||
else if (ch == EOI) {
|
||||
lexerror("unterminated comment");
|
||||
break;
|
||||
}
|
||||
LoadChar(ch);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC struct string *
|
||||
GetString(upto)
|
||||
{
|
||||
/* Read a Modula-2 string, delimited by the character "upto".
|
||||
*/
|
||||
register int ch;
|
||||
register struct string *str = (struct string *)
|
||||
Malloc((unsigned) sizeof(struct string));
|
||||
register char *p;
|
||||
register int len;
|
||||
|
||||
len = ISTRSIZE;
|
||||
str->s_str = p = Malloc((unsigned int) ISTRSIZE);
|
||||
while (LoadChar(ch), ch != upto) {
|
||||
if (class(ch) == STNL) {
|
||||
lexerror("newline in string");
|
||||
LineNumber++;
|
||||
#ifdef DEBUG
|
||||
cntlines++;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (ch == EOI) {
|
||||
lexerror("end-of-file in string");
|
||||
break;
|
||||
}
|
||||
*p++ = ch;
|
||||
if (p - str->s_str == len) {
|
||||
str->s_str = Realloc(str->s_str,
|
||||
(unsigned int) len + RSTRSIZE);
|
||||
p = str->s_str + len;
|
||||
len += RSTRSIZE;
|
||||
}
|
||||
}
|
||||
str->s_length = p - str->s_str;
|
||||
while (p - str->s_str < len) *p++ = '\0';
|
||||
if (str->s_length == 0) str->s_length = 1;
|
||||
/* ??? string length at least 1 ??? */
|
||||
return str;
|
||||
}
|
||||
|
||||
static char *s_error = "illegal line directive";
|
||||
|
||||
STATIC int
|
||||
getch()
|
||||
{
|
||||
register int ch;
|
||||
|
||||
for (;;) {
|
||||
LoadChar(ch);
|
||||
if ((ch & 0200) && ch != EOI) {
|
||||
error("non-ascii '\\%03o' read", ch & 0377);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ch == EOI) {
|
||||
eofseen = 1;
|
||||
return '\n';
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
CheckForLineDirective()
|
||||
{
|
||||
register int ch = getch();
|
||||
register int i = 0;
|
||||
char buf[IDFSIZE + 2];
|
||||
register char *c = buf;
|
||||
|
||||
|
||||
if (ch != '#') {
|
||||
PushBack();
|
||||
return;
|
||||
}
|
||||
do { /*
|
||||
* Skip to next digit
|
||||
* Do not skip newlines
|
||||
*/
|
||||
ch = getch();
|
||||
if (class(ch) == STNL) {
|
||||
LineNumber++;
|
||||
error(s_error);
|
||||
return;
|
||||
}
|
||||
} while (class(ch) != STNUM);
|
||||
while (class(ch) == STNUM) {
|
||||
i = i*10 + (ch - '0');
|
||||
ch = getch();
|
||||
}
|
||||
while (ch != '"' && class(ch) != STNL) ch = getch();
|
||||
if (ch == '"') {
|
||||
c = buf;
|
||||
do {
|
||||
*c++ = ch = getch();
|
||||
if (class(ch) == STNL) {
|
||||
LineNumber++;
|
||||
error(s_error);
|
||||
return;
|
||||
}
|
||||
} while (ch != '"');
|
||||
*--c = '\0';
|
||||
do {
|
||||
ch = getch();
|
||||
} while (class(ch) != STNL);
|
||||
/*
|
||||
* Remember the file name
|
||||
*/
|
||||
if (!eofseen && strcmp(FileName,buf)) {
|
||||
FileName = Salloc(buf,(unsigned) strlen(buf) + 1);
|
||||
}
|
||||
}
|
||||
if (eofseen) {
|
||||
error(s_error);
|
||||
return;
|
||||
}
|
||||
LineNumber = i;
|
||||
}
|
||||
|
||||
int
|
||||
LLlex()
|
||||
{
|
||||
/* LLlex() is the Lexical Analyzer.
|
||||
The putting aside of tokens is taken into account.
|
||||
*/
|
||||
register struct token *tk = ˙
|
||||
char buf[(IDFSIZE > NUMSIZE ? IDFSIZE : NUMSIZE) + 2];
|
||||
register int ch, nch;
|
||||
|
||||
toktype = error_type;
|
||||
|
||||
if (ASIDE) { /* a token is put aside */
|
||||
*tk = aside;
|
||||
ASIDE = 0;
|
||||
return tk->tk_symb;
|
||||
}
|
||||
|
||||
again1:
|
||||
if (eofseen) {
|
||||
eofseen = 0;
|
||||
ch = EOI;
|
||||
}
|
||||
else {
|
||||
again:
|
||||
LoadChar(ch);
|
||||
if ((ch & 0200) && ch != EOI) {
|
||||
error("non-ascii '\\%03o' read", ch & 0377);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
tk->tk_lineno = LineNumber;
|
||||
|
||||
switch (class(ch)) {
|
||||
|
||||
case STNL:
|
||||
LineNumber++;
|
||||
#ifdef DEBUG
|
||||
cntlines++;
|
||||
#endif
|
||||
CheckForLineDirective();
|
||||
goto again1;
|
||||
|
||||
case STSKIP:
|
||||
goto again;
|
||||
|
||||
case STGARB:
|
||||
if ((unsigned) ch - 040 < 0137) {
|
||||
lexerror("garbage char %c", ch);
|
||||
}
|
||||
else lexerror("garbage char \\%03o", ch);
|
||||
goto again;
|
||||
|
||||
case STSIMP:
|
||||
if (ch == '(') {
|
||||
LoadChar(nch);
|
||||
if (nch == '*') {
|
||||
SkipComment();
|
||||
goto again;
|
||||
}
|
||||
else if (nch == EOI) eofseen = 1;
|
||||
else PushBack();
|
||||
}
|
||||
if (ch == '&') return tk->tk_symb = AND;
|
||||
if (ch == '~') return tk->tk_symb = NOT;
|
||||
return tk->tk_symb = ch;
|
||||
|
||||
case STCOMP:
|
||||
LoadChar(nch);
|
||||
switch (ch) {
|
||||
|
||||
case '.':
|
||||
if (nch == '.') {
|
||||
return tk->tk_symb = UPTO;
|
||||
}
|
||||
break;
|
||||
|
||||
case ':':
|
||||
if (nch == '=') {
|
||||
return tk->tk_symb = BECOMES;
|
||||
}
|
||||
break;
|
||||
|
||||
case '<':
|
||||
if (nch == '=') {
|
||||
return tk->tk_symb = LESSEQUAL;
|
||||
}
|
||||
if (nch == '>') {
|
||||
return tk->tk_symb = '#';
|
||||
}
|
||||
break;
|
||||
|
||||
case '>':
|
||||
if (nch == '=') {
|
||||
return tk->tk_symb = GREATEREQUAL;
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
crash("(LLlex, STCOMP)");
|
||||
}
|
||||
if (nch == EOI) eofseen = 1;
|
||||
else PushBack();
|
||||
return tk->tk_symb = ch;
|
||||
|
||||
case STIDF:
|
||||
{
|
||||
register char *tag = &buf[0];
|
||||
register struct idf *id;
|
||||
|
||||
do {
|
||||
if (tag - buf < idfsize) *tag++ = ch;
|
||||
LoadChar(ch);
|
||||
} while(in_idf(ch));
|
||||
|
||||
if (ch == EOI) eofseen = 1;
|
||||
else PushBack();
|
||||
*tag++ = '\0';
|
||||
|
||||
tk->TOK_IDF = id = str2idf(buf, 1);
|
||||
return tk->tk_symb = id->id_reserved ? id->id_reserved : IDENT;
|
||||
}
|
||||
|
||||
case STSTR: {
|
||||
register struct string *str = GetString(ch);
|
||||
|
||||
if (str->s_length == 1) {
|
||||
tk->TOK_INT = *(str->s_str) & 0377;
|
||||
toktype = char_type;
|
||||
free(str->s_str);
|
||||
free((char *) str);
|
||||
}
|
||||
else {
|
||||
tk->tk_data.tk_str = str;
|
||||
toktype = standard_type(T_STRING, 1, str->s_length);
|
||||
}
|
||||
return tk->tk_symb = STRING;
|
||||
}
|
||||
|
||||
case STNUM:
|
||||
{
|
||||
/* The problem arising with the "parsing" of a number
|
||||
is that we don't know the base in advance so we
|
||||
have to read the number with the help of a rather
|
||||
complex finite automaton.
|
||||
*/
|
||||
enum statetp {Oct,OptHex,Hex,Dec,OctEndOrHex,End,OptReal,Real};
|
||||
register enum statetp state;
|
||||
register int base;
|
||||
register char *np = &buf[1];
|
||||
/* allow a '-' to be added */
|
||||
|
||||
buf[0] = '-';
|
||||
*np++ = ch;
|
||||
state = is_oct(ch) ? Oct : Dec;
|
||||
LoadChar(ch);
|
||||
for (;;) {
|
||||
switch(state) {
|
||||
case Oct:
|
||||
while (is_oct(ch)) {
|
||||
if (np < &buf[NUMSIZE]) *np++ = ch;
|
||||
LoadChar(ch);
|
||||
}
|
||||
if (ch == 'B' || ch == 'C') {
|
||||
base = 8;
|
||||
state = OctEndOrHex;
|
||||
break;
|
||||
}
|
||||
/* Fall Through */
|
||||
case Dec:
|
||||
base = 10;
|
||||
while (is_dig(ch)) {
|
||||
if (np < &buf[NUMSIZE]) {
|
||||
*np++ = ch;
|
||||
}
|
||||
LoadChar(ch);
|
||||
}
|
||||
if (ch == 'D') state = OptHex;
|
||||
else if (is_hex(ch)) state = Hex;
|
||||
else if (ch == '.') state = OptReal;
|
||||
else {
|
||||
state = End;
|
||||
if (ch == 'H') base = 16;
|
||||
else if (ch == EOI) eofseen = 1;
|
||||
else PushBack();
|
||||
}
|
||||
break;
|
||||
|
||||
case OptHex:
|
||||
LoadChar(ch);
|
||||
if (is_hex(ch)) {
|
||||
if (np < &buf[NUMSIZE]) *np++ = 'D';
|
||||
state = Hex;
|
||||
}
|
||||
else state = End;
|
||||
break;
|
||||
|
||||
case Hex:
|
||||
while (is_hex(ch)) {
|
||||
if (np < &buf[NUMSIZE]) *np++ = ch;
|
||||
LoadChar(ch);
|
||||
}
|
||||
base = 16;
|
||||
state = End;
|
||||
if (ch != 'H') {
|
||||
lexerror("H expected after hex number");
|
||||
if (ch == EOI) eofseen = 1;
|
||||
else PushBack();
|
||||
}
|
||||
break;
|
||||
|
||||
case OctEndOrHex:
|
||||
if (np < &buf[NUMSIZE]) *np++ = ch;
|
||||
LoadChar(ch);
|
||||
if (ch == 'H') {
|
||||
base = 16;
|
||||
state = End;
|
||||
break;
|
||||
}
|
||||
if (is_hex(ch)) {
|
||||
state = Hex;
|
||||
break;
|
||||
}
|
||||
if (ch == EOI) eofseen = 1;
|
||||
else PushBack();
|
||||
ch = *--np;
|
||||
*np++ = '\0';
|
||||
base = 8;
|
||||
/* Fall through */
|
||||
|
||||
case End:
|
||||
*np = '\0';
|
||||
if (np >= &buf[NUMSIZE]) {
|
||||
tk->TOK_INT = 1;
|
||||
lexerror("constant too long");
|
||||
}
|
||||
else {
|
||||
np = &buf[1];
|
||||
while (*np == '0') np++;
|
||||
tk->TOK_INT = str2long(np, base);
|
||||
if (strlen(np) > 14 /* ??? */ ||
|
||||
tk->TOK_INT < 0) {
|
||||
lexwarning(W_ORDINARY, "overflow in constant");
|
||||
}
|
||||
}
|
||||
if (ch == 'C' && base == 8) {
|
||||
toktype = char_type;
|
||||
if (tk->TOK_INT<0 || tk->TOK_INT>255) {
|
||||
lexwarning(W_ORDINARY, "character constant out of range");
|
||||
}
|
||||
}
|
||||
else if (ch == 'D' && base == 10) {
|
||||
toktype = longint_type;
|
||||
}
|
||||
else if (tk->TOK_INT>=0 &&
|
||||
tk->TOK_INT<=max_int) {
|
||||
toktype = intorcard_type;
|
||||
}
|
||||
else toktype = card_type;
|
||||
return tk->tk_symb = INTEGER;
|
||||
|
||||
case OptReal:
|
||||
/* The '.' could be the first of the '..'
|
||||
token. At this point, we need a
|
||||
look-ahead of two characters.
|
||||
*/
|
||||
LoadChar(ch);
|
||||
if (ch == '.') {
|
||||
/* Indeed the '..' token
|
||||
*/
|
||||
PushBack();
|
||||
PushBack();
|
||||
state = End;
|
||||
base = 10;
|
||||
break;
|
||||
}
|
||||
state = Real;
|
||||
break;
|
||||
}
|
||||
if (state == Real) break;
|
||||
}
|
||||
|
||||
/* a real real constant */
|
||||
if (np < &buf[NUMSIZE]) *np++ = '.';
|
||||
|
||||
toktype = real_type;
|
||||
|
||||
while (is_dig(ch)) {
|
||||
/* Fractional part
|
||||
*/
|
||||
if (np < &buf[NUMSIZE]) *np++ = ch;
|
||||
LoadChar(ch);
|
||||
}
|
||||
|
||||
if (ch == 'E' || ch == 'D') {
|
||||
/* Scale factor
|
||||
*/
|
||||
if (ch == 'D') {
|
||||
toktype = longreal_type;
|
||||
LoadChar(ch);
|
||||
if (!(ch == '+' || ch == '-' || is_dig(ch)))
|
||||
goto noscale;
|
||||
}
|
||||
if (np < &buf[NUMSIZE]) *np++ = 'E';
|
||||
LoadChar(ch);
|
||||
if (ch == '+' || ch == '-') {
|
||||
/* Signed scalefactor
|
||||
*/
|
||||
if (np < &buf[NUMSIZE]) *np++ = ch;
|
||||
LoadChar(ch);
|
||||
}
|
||||
if (is_dig(ch)) {
|
||||
do {
|
||||
if (np < &buf[NUMSIZE]) *np++ = ch;
|
||||
LoadChar(ch);
|
||||
} while (is_dig(ch));
|
||||
}
|
||||
else {
|
||||
lexerror("bad scale factor");
|
||||
}
|
||||
}
|
||||
|
||||
noscale:
|
||||
*np++ = '\0';
|
||||
if (ch == EOI) eofseen = 1;
|
||||
else PushBack();
|
||||
|
||||
if (np >= &buf[NUMSIZE]) {
|
||||
tk->TOK_REL = Salloc("0.0", 5);
|
||||
lexerror("floating constant too long");
|
||||
}
|
||||
else tk->TOK_REL = Salloc(buf, (unsigned) (np - buf)) + 1;
|
||||
return tk->tk_symb = REAL;
|
||||
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
case STEOI:
|
||||
return tk->tk_symb = -1;
|
||||
|
||||
case STCHAR:
|
||||
default:
|
||||
crash("(LLlex) Impossible character class");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
45
lang/m2/comp/LLlex.h
Normal file
45
lang/m2/comp/LLlex.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* T O K E N D E S C R I P T O R D E F I N I T I O N */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* Structure to store a string constant
|
||||
*/
|
||||
struct string {
|
||||
arith s_length; /* length of a string */
|
||||
char *s_str; /* the string itself */
|
||||
};
|
||||
|
||||
/* Token structure. Keep it small, as it is part of a parse-tree node
|
||||
*/
|
||||
struct token {
|
||||
short tk_symb; /* token itself */
|
||||
unsigned short tk_lineno; /* linenumber on which it occurred */
|
||||
union {
|
||||
struct idf *tk_idf; /* IDENT */
|
||||
struct string *tk_str; /* STRING */
|
||||
arith tk_int; /* INTEGER */
|
||||
char *tk_real; /* REAL */
|
||||
arith *tk_set; /* only used in parse tree node */
|
||||
struct def *tk_def; /* only used in parse tree node */
|
||||
label tk_lab; /* only used in parse tree node */
|
||||
} tk_data;
|
||||
};
|
||||
|
||||
#define TOK_IDF tk_data.tk_idf
|
||||
#define TOK_STR tk_data.tk_str->s_str
|
||||
#define TOK_SLE tk_data.tk_str->s_length
|
||||
#define TOK_INT tk_data.tk_int
|
||||
#define TOK_REL tk_data.tk_real
|
||||
|
||||
extern struct token dot, aside;
|
||||
extern struct type *toktype;
|
||||
|
||||
#define DOT dot.tk_symb
|
||||
#define ASIDE aside.tk_symb
|
||||
67
lang/m2/comp/LLmessage.c
Normal file
67
lang/m2/comp/LLmessage.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* S Y N T A X E R R O R R E P O R T I N G */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* Defines the LLmessage routine. LLgen-generated parsers require the
|
||||
existence of a routine of that name.
|
||||
The routine must do syntax-error reporting and must be able to
|
||||
insert tokens in the token stream.
|
||||
*/
|
||||
|
||||
#include <alloc.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
|
||||
#include "idf.h"
|
||||
#include "LLlex.h"
|
||||
#include "Lpars.h"
|
||||
|
||||
extern char *symbol2str();
|
||||
extern struct idf *gen_anon_idf();
|
||||
|
||||
LLmessage(tk)
|
||||
register int tk;
|
||||
{
|
||||
if (tk > 0) {
|
||||
/* if (tk > 0), it represents the token to be inserted.
|
||||
*/
|
||||
register struct token *dotp = ˙
|
||||
|
||||
error("%s missing", symbol2str(tk));
|
||||
|
||||
aside = *dotp;
|
||||
|
||||
dotp->tk_symb = tk;
|
||||
|
||||
switch (tk) {
|
||||
/* The operands need some body */
|
||||
case IDENT:
|
||||
dotp->TOK_IDF = gen_anon_idf();
|
||||
break;
|
||||
case STRING:
|
||||
dotp->tk_data.tk_str = (struct string *)
|
||||
Malloc(sizeof (struct string));
|
||||
dotp->TOK_SLE = 1;
|
||||
dotp->TOK_STR = Salloc("", 1);
|
||||
break;
|
||||
case INTEGER:
|
||||
dotp->TOK_INT = 1;
|
||||
break;
|
||||
case REAL:
|
||||
dotp->TOK_REL = Salloc("0.0", 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (tk < 0) {
|
||||
error("garbage at end of program");
|
||||
}
|
||||
else error("%s deleted", symbol2str(dot.tk_symb));
|
||||
}
|
||||
|
||||
8
lang/m2/comp/MakeVersion
Executable file
8
lang/m2/comp/MakeVersion
Executable file
@@ -0,0 +1,8 @@
|
||||
V=`cat Version.c`
|
||||
VERSION=`expr "$V" ':' '.*[0-9][0-9]*\.\([0-9][0-9]*\).*'`
|
||||
NEWVERSION=`expr $VERSION + 1`
|
||||
sed "s/\.$VERSION/.$NEWVERSION/" < Version.c > tmp$$
|
||||
mv tmp$$ Version.c
|
||||
CM "$*"
|
||||
V=`cat Version.c`
|
||||
SV > ../versions/V`expr "$V" ':' '.*\([0-9][0-9]*\.[0-9][0-9]*\).*'`
|
||||
419
lang/m2/comp/Makefile
Normal file
419
lang/m2/comp/Makefile
Normal file
@@ -0,0 +1,419 @@
|
||||
# make modula-2 "compiler"
|
||||
EMHOME = ../../..
|
||||
MHDIR = $(EMHOME)/modules/h
|
||||
PKGDIR = $(EMHOME)/modules/pkg
|
||||
LIBDIR = $(EMHOME)/modules/lib
|
||||
OBJECTCODE = $(LIBDIR)/libemk.a
|
||||
LLGEN = $(EMHOME)/bin/LLgen
|
||||
MKDEP = $(EMHOME)/bin/mkdep
|
||||
PRID = $(EMHOME)/bin/prid
|
||||
CID = $(EMHOME)/bin/cid
|
||||
CURRDIR = .
|
||||
|
||||
INCLUDES = -I$(MHDIR) -I$(EMHOME)/h -I$(PKGDIR)
|
||||
|
||||
GF = program.g declar.g expression.g statement.g
|
||||
GENGFILES= tokenfile.g
|
||||
GFILES =$(GENGFILES) $(GF)
|
||||
LLGENOPTIONS = -v
|
||||
PROFILE =
|
||||
CFLAGS = $(PROFILE) $(INCLUDES) -O -DSTATIC=
|
||||
LINTFLAGS = -DSTATIC= -DNORCSID
|
||||
MALLOC = $(LIBDIR)/malloc.o
|
||||
LDFLAGS = -i $(PROFILE)
|
||||
LSRC = tokenfile.c program.c declar.c expression.c statement.c
|
||||
LOBJ = tokenfile.o program.o declar.o expression.o statement.o
|
||||
CSRC = LLlex.c LLmessage.c error.c main.c \
|
||||
tokenname.c idf.c input.c type.c def.c \
|
||||
misc.c enter.c defmodule.c typequiv.c node.c \
|
||||
cstoper.c chk_expr.c options.c walk.c desig.c \
|
||||
code.c lookup.c Version.c
|
||||
COBJ = LLlex.o LLmessage.o char.o error.o main.o \
|
||||
symbol2str.o tokenname.o idf.o input.o type.o def.o \
|
||||
scope.o misc.o enter.o defmodule.o typequiv.o node.o \
|
||||
cstoper.o chk_expr.o options.o walk.o casestat.o desig.o \
|
||||
code.o tmpvar.o lookup.o Version.o next.o
|
||||
GENC= $(LSRC) symbol2str.c char.c Lpars.c casestat.c tmpvar.c scope.c next.c
|
||||
SRC = $(CSRC) $(GENC)
|
||||
OBJ = $(COBJ) $(LOBJ) Lpars.o
|
||||
|
||||
GENH= errout.h\
|
||||
idfsize.h numsize.h strsize.h target_sizes.h \
|
||||
inputtype.h maxset.h density.h\
|
||||
def.h debugcst.h type.h Lpars.h node.h desig.h
|
||||
HFILES= LLlex.h\
|
||||
chk_expr.h class.h const.h debug.h f_info.h idf.h\
|
||||
input.h main.h misc.h scope.h standards.h tokenname.h\
|
||||
walk.h warning.h SYSTEM.h $(GENH)
|
||||
#
|
||||
GENFILES = $(GENGFILES) $(GENC) $(GENH)
|
||||
NEXTFILES = def.H type.H node.H desig.H scope.C tmpvar.C casestat.C
|
||||
|
||||
#EXCLEXCLEXCLEXCL
|
||||
|
||||
all: Cfiles
|
||||
sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) $(CURRDIR)/main ; else EMHOME=$(EMHOME); export EMHOME; sh Resolve main ; fi'
|
||||
@rm -f nmclash.o a.out
|
||||
|
||||
install: all
|
||||
cp $(CURRDIR)/main $(EMHOME)/lib/em_m2
|
||||
rm -f $(EMHOME)/man/em_m2.6 $(EMHOME)/man/modula-2.1
|
||||
cp $(CURRDIR)/em_m2.6 $(CURRDIR)/modula-2.1 $(EMHOME)/man
|
||||
|
||||
cmp: all
|
||||
-cmp $(CURRDIR)/main $(EMHOME)/lib/em_m2
|
||||
-cmp $(CURRDIR)/em_m2.6 $(EMHOME)/man/em_m2.6
|
||||
-cmp $(CURRDIR)/modula-2.1 $(EMHOME)/man/modula-2.1
|
||||
|
||||
opr:
|
||||
make pr | opr
|
||||
|
||||
pr:
|
||||
@pr Makefile Resolve Parameters $(GF) *.H $(HFILES) *.C $(CSRC)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) $(GENFILES) LLfiles hfiles Cfiles tab clashes \
|
||||
$(CURRDIR)/main LL.output
|
||||
(cd .. ; rm -rf Xsrc)
|
||||
|
||||
lint: Cfiles
|
||||
sh -c 'if $(CC) nmclash.c > /dev/null 2>&1 ; then make "EMHOME="$(EMHOME) Xlint ; else EMHOME=$(EMHOME); export EMHOME; sh Resolve Xlint ; fi'
|
||||
@rm -f nmclash.o a.out
|
||||
|
||||
longnames: $(SRC) $(HFILES)
|
||||
sh -c 'if test -f longnames ; then $(PRID) -l7 longnames $? > Xlongnames ; mv Xlongnames longnames ; else $(PRID) -l7 $? > longnames ; fi'
|
||||
|
||||
# entry points not to be used directly
|
||||
|
||||
Cfiles: hfiles LLfiles $(GENC) $(GENH) Makefile
|
||||
echo $(SRC) $(HFILES) > Cfiles
|
||||
|
||||
LLfiles: $(GFILES)
|
||||
$(LLGEN) $(LLGENOPTIONS) $(GFILES)
|
||||
@touch LLfiles
|
||||
|
||||
hfiles: Parameters make.hfiles
|
||||
make.hfiles Parameters
|
||||
touch hfiles
|
||||
|
||||
tokenfile.g: tokenname.c make.tokfile
|
||||
make.tokfile <tokenname.c >tokenfile.g
|
||||
|
||||
symbol2str.c: tokenname.c make.tokcase
|
||||
make.tokcase <tokenname.c >symbol2str.c
|
||||
|
||||
.SUFFIXES: .H .h
|
||||
.H.h:
|
||||
./make.allocd < $*.H > $*.h
|
||||
|
||||
.SUFFIXES: .C .c
|
||||
.C.c:
|
||||
./make.allocd < $*.C > $*.c
|
||||
|
||||
def.h: make.allocd
|
||||
type.h: make.allocd
|
||||
node.h: make.allocd
|
||||
desig.h: make.allocd
|
||||
scope.c: make.allocd
|
||||
tmpvar.c: make.allocd
|
||||
casestat.c: make.allocd
|
||||
|
||||
next.c: $(NEXTFILES) ./make.next
|
||||
./make.next $(NEXTFILES) > next.c
|
||||
|
||||
char.c: char.tab tab
|
||||
tab -fchar.tab >char.c
|
||||
|
||||
tab:
|
||||
$(CC) tab.c -o tab
|
||||
|
||||
depend:
|
||||
sed '/^#AUTOAUTO/,$$d' Makefile > Makefile.new
|
||||
echo '#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO' >> Makefile.new
|
||||
$(MKDEP) $(SRC) |\
|
||||
sed 's/\.c:/\.o:/' >> Makefile.new
|
||||
mv Makefile Makefile.old
|
||||
mv Makefile.new Makefile
|
||||
|
||||
#INCLINCLINCLINCL
|
||||
|
||||
Xlint:
|
||||
lint $(INCLUDES) $(LINTFLAGS) $(SRC) \
|
||||
$(LIBDIR)/llib-lem_mes.ln \
|
||||
$(LIBDIR)/llib-lemk.ln \
|
||||
$(LIBDIR)/llib-linput.ln \
|
||||
$(LIBDIR)/llib-lassert.ln \
|
||||
$(LIBDIR)/llib-lalloc.ln \
|
||||
$(LIBDIR)/llib-lprint.ln \
|
||||
$(LIBDIR)/llib-lstring.ln \
|
||||
$(LIBDIR)/llib-lsystem.ln
|
||||
|
||||
$(CURRDIR)/main: $(OBJ)
|
||||
$(CC) $(LDFLAGS) $(OBJ) $(LIBDIR)/libem_mes.a $(OBJECTCODE) $(LIBDIR)/libinput.a $(LIBDIR)/libassert.a $(LIBDIR)/liballoc.a $(MALLOC) $(LIBDIR)/libprint.a $(LIBDIR)/libstring.a $(LIBDIR)/libsystem.a -o $(CURRDIR)/main
|
||||
size $(CURRDIR)/main
|
||||
|
||||
#AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO
|
||||
LLlex.o: LLlex.h
|
||||
LLlex.o: Lpars.h
|
||||
LLlex.o: class.h
|
||||
LLlex.o: const.h
|
||||
LLlex.o: debug.h
|
||||
LLlex.o: debugcst.h
|
||||
LLlex.o: def.h
|
||||
LLlex.o: f_info.h
|
||||
LLlex.o: idf.h
|
||||
LLlex.o: idfsize.h
|
||||
LLlex.o: input.h
|
||||
LLlex.o: inputtype.h
|
||||
LLlex.o: numsize.h
|
||||
LLlex.o: strsize.h
|
||||
LLlex.o: type.h
|
||||
LLlex.o: warning.h
|
||||
LLmessage.o: LLlex.h
|
||||
LLmessage.o: Lpars.h
|
||||
LLmessage.o: idf.h
|
||||
error.o: LLlex.h
|
||||
error.o: debug.h
|
||||
error.o: debugcst.h
|
||||
error.o: errout.h
|
||||
error.o: f_info.h
|
||||
error.o: input.h
|
||||
error.o: inputtype.h
|
||||
error.o: main.h
|
||||
error.o: node.h
|
||||
error.o: warning.h
|
||||
main.o: LLlex.h
|
||||
main.o: Lpars.h
|
||||
main.o: SYSTEM.h
|
||||
main.o: debug.h
|
||||
main.o: debugcst.h
|
||||
main.o: def.h
|
||||
main.o: f_info.h
|
||||
main.o: idf.h
|
||||
main.o: input.h
|
||||
main.o: inputtype.h
|
||||
main.o: node.h
|
||||
main.o: scope.h
|
||||
main.o: standards.h
|
||||
main.o: tokenname.h
|
||||
main.o: type.h
|
||||
main.o: warning.h
|
||||
tokenname.o: Lpars.h
|
||||
tokenname.o: idf.h
|
||||
tokenname.o: tokenname.h
|
||||
idf.o: idf.h
|
||||
input.o: f_info.h
|
||||
input.o: input.h
|
||||
input.o: inputtype.h
|
||||
type.o: LLlex.h
|
||||
type.o: chk_expr.h
|
||||
type.o: const.h
|
||||
type.o: debug.h
|
||||
type.o: debugcst.h
|
||||
type.o: def.h
|
||||
type.o: idf.h
|
||||
type.o: maxset.h
|
||||
type.o: node.h
|
||||
type.o: scope.h
|
||||
type.o: target_sizes.h
|
||||
type.o: type.h
|
||||
type.o: walk.h
|
||||
def.o: LLlex.h
|
||||
def.o: Lpars.h
|
||||
def.o: debug.h
|
||||
def.o: debugcst.h
|
||||
def.o: def.h
|
||||
def.o: idf.h
|
||||
def.o: main.h
|
||||
def.o: node.h
|
||||
def.o: scope.h
|
||||
def.o: type.h
|
||||
misc.o: LLlex.h
|
||||
misc.o: f_info.h
|
||||
misc.o: idf.h
|
||||
misc.o: misc.h
|
||||
misc.o: node.h
|
||||
enter.o: LLlex.h
|
||||
enter.o: debug.h
|
||||
enter.o: debugcst.h
|
||||
enter.o: def.h
|
||||
enter.o: f_info.h
|
||||
enter.o: idf.h
|
||||
enter.o: main.h
|
||||
enter.o: misc.h
|
||||
enter.o: node.h
|
||||
enter.o: scope.h
|
||||
enter.o: type.h
|
||||
defmodule.o: LLlex.h
|
||||
defmodule.o: Lpars.h
|
||||
defmodule.o: debug.h
|
||||
defmodule.o: debugcst.h
|
||||
defmodule.o: def.h
|
||||
defmodule.o: f_info.h
|
||||
defmodule.o: idf.h
|
||||
defmodule.o: input.h
|
||||
defmodule.o: inputtype.h
|
||||
defmodule.o: main.h
|
||||
defmodule.o: misc.h
|
||||
defmodule.o: node.h
|
||||
defmodule.o: scope.h
|
||||
defmodule.o: type.h
|
||||
typequiv.o: LLlex.h
|
||||
typequiv.o: debug.h
|
||||
typequiv.o: debugcst.h
|
||||
typequiv.o: def.h
|
||||
typequiv.o: idf.h
|
||||
typequiv.o: node.h
|
||||
typequiv.o: type.h
|
||||
typequiv.o: warning.h
|
||||
node.o: LLlex.h
|
||||
node.o: debug.h
|
||||
node.o: debugcst.h
|
||||
node.o: def.h
|
||||
node.o: node.h
|
||||
node.o: type.h
|
||||
cstoper.o: LLlex.h
|
||||
cstoper.o: Lpars.h
|
||||
cstoper.o: debug.h
|
||||
cstoper.o: debugcst.h
|
||||
cstoper.o: idf.h
|
||||
cstoper.o: node.h
|
||||
cstoper.o: standards.h
|
||||
cstoper.o: target_sizes.h
|
||||
cstoper.o: type.h
|
||||
cstoper.o: warning.h
|
||||
chk_expr.o: LLlex.h
|
||||
chk_expr.o: Lpars.h
|
||||
chk_expr.o: chk_expr.h
|
||||
chk_expr.o: const.h
|
||||
chk_expr.o: debug.h
|
||||
chk_expr.o: debugcst.h
|
||||
chk_expr.o: def.h
|
||||
chk_expr.o: idf.h
|
||||
chk_expr.o: misc.h
|
||||
chk_expr.o: node.h
|
||||
chk_expr.o: scope.h
|
||||
chk_expr.o: standards.h
|
||||
chk_expr.o: type.h
|
||||
chk_expr.o: warning.h
|
||||
options.o: idfsize.h
|
||||
options.o: main.h
|
||||
options.o: type.h
|
||||
options.o: warning.h
|
||||
walk.o: LLlex.h
|
||||
walk.o: Lpars.h
|
||||
walk.o: chk_expr.h
|
||||
walk.o: debug.h
|
||||
walk.o: debugcst.h
|
||||
walk.o: def.h
|
||||
walk.o: desig.h
|
||||
walk.o: f_info.h
|
||||
walk.o: idf.h
|
||||
walk.o: main.h
|
||||
walk.o: node.h
|
||||
walk.o: scope.h
|
||||
walk.o: type.h
|
||||
walk.o: walk.h
|
||||
walk.o: warning.h
|
||||
desig.o: LLlex.h
|
||||
desig.o: debug.h
|
||||
desig.o: debugcst.h
|
||||
desig.o: def.h
|
||||
desig.o: desig.h
|
||||
desig.o: node.h
|
||||
desig.o: scope.h
|
||||
desig.o: type.h
|
||||
code.o: LLlex.h
|
||||
code.o: Lpars.h
|
||||
code.o: debug.h
|
||||
code.o: debugcst.h
|
||||
code.o: def.h
|
||||
code.o: desig.h
|
||||
code.o: node.h
|
||||
code.o: scope.h
|
||||
code.o: standards.h
|
||||
code.o: type.h
|
||||
code.o: walk.h
|
||||
lookup.o: LLlex.h
|
||||
lookup.o: debug.h
|
||||
lookup.o: debugcst.h
|
||||
lookup.o: def.h
|
||||
lookup.o: idf.h
|
||||
lookup.o: misc.h
|
||||
lookup.o: node.h
|
||||
lookup.o: scope.h
|
||||
lookup.o: type.h
|
||||
tokenfile.o: Lpars.h
|
||||
program.o: LLlex.h
|
||||
program.o: Lpars.h
|
||||
program.o: debug.h
|
||||
program.o: debugcst.h
|
||||
program.o: def.h
|
||||
program.o: f_info.h
|
||||
program.o: idf.h
|
||||
program.o: main.h
|
||||
program.o: node.h
|
||||
program.o: scope.h
|
||||
program.o: type.h
|
||||
program.o: warning.h
|
||||
declar.o: LLlex.h
|
||||
declar.o: Lpars.h
|
||||
declar.o: chk_expr.h
|
||||
declar.o: debug.h
|
||||
declar.o: debugcst.h
|
||||
declar.o: def.h
|
||||
declar.o: idf.h
|
||||
declar.o: main.h
|
||||
declar.o: misc.h
|
||||
declar.o: node.h
|
||||
declar.o: scope.h
|
||||
declar.o: type.h
|
||||
declar.o: warning.h
|
||||
expression.o: LLlex.h
|
||||
expression.o: Lpars.h
|
||||
expression.o: chk_expr.h
|
||||
expression.o: const.h
|
||||
expression.o: debug.h
|
||||
expression.o: debugcst.h
|
||||
expression.o: def.h
|
||||
expression.o: idf.h
|
||||
expression.o: node.h
|
||||
expression.o: type.h
|
||||
expression.o: warning.h
|
||||
statement.o: LLlex.h
|
||||
statement.o: Lpars.h
|
||||
statement.o: def.h
|
||||
statement.o: idf.h
|
||||
statement.o: node.h
|
||||
statement.o: scope.h
|
||||
statement.o: type.h
|
||||
symbol2str.o: Lpars.h
|
||||
char.o: class.h
|
||||
Lpars.o: Lpars.h
|
||||
casestat.o: LLlex.h
|
||||
casestat.o: Lpars.h
|
||||
casestat.o: chk_expr.h
|
||||
casestat.o: debug.h
|
||||
casestat.o: debugcst.h
|
||||
casestat.o: density.h
|
||||
casestat.o: desig.h
|
||||
casestat.o: node.h
|
||||
casestat.o: type.h
|
||||
casestat.o: walk.h
|
||||
tmpvar.o: LLlex.h
|
||||
tmpvar.o: debug.h
|
||||
tmpvar.o: debugcst.h
|
||||
tmpvar.o: def.h
|
||||
tmpvar.o: main.h
|
||||
tmpvar.o: scope.h
|
||||
tmpvar.o: type.h
|
||||
scope.o: LLlex.h
|
||||
scope.o: debug.h
|
||||
scope.o: debugcst.h
|
||||
scope.o: def.h
|
||||
scope.o: idf.h
|
||||
scope.o: node.h
|
||||
scope.o: scope.h
|
||||
scope.o: type.h
|
||||
next.o: debug.h
|
||||
next.o: debugcst.h
|
||||
61
lang/m2/comp/Parameters
Normal file
61
lang/m2/comp/Parameters
Normal file
@@ -0,0 +1,61 @@
|
||||
!File: errout.h
|
||||
#define ERROUT STDERR /* file pointer for writing messages */
|
||||
#define MAXERR_LINE 100 /* maximum number of error messages given
|
||||
on the same input line. */
|
||||
|
||||
|
||||
!File: idfsize.h
|
||||
#define IDFSIZE 128 /* maximum significant length of an identifier */
|
||||
|
||||
|
||||
!File: numsize.h
|
||||
#define NUMSIZE 256 /* maximum length of a numeric constant */
|
||||
|
||||
|
||||
!File: strsize.h
|
||||
#define ISTRSIZE 32 /* minimum number of bytes allocated for
|
||||
storing a string */
|
||||
#define RSTRSIZE 8 /* step size in enlarging the memory for
|
||||
the storage of a string */
|
||||
|
||||
|
||||
!File: target_sizes.h
|
||||
#define MAXSIZE 8 /* the maximum of the SZ_* constants */
|
||||
|
||||
/* target machine sizes */
|
||||
#define SZ_CHAR (arith)1
|
||||
#define SZ_SHORT (arith)2
|
||||
#define SZ_WORD (arith)4
|
||||
#define SZ_INT (arith)4
|
||||
#define SZ_LONG (arith)4
|
||||
#define SZ_FLOAT (arith)4
|
||||
#define SZ_DOUBLE (arith)8
|
||||
#define SZ_POINTER (arith)4
|
||||
|
||||
/* target machine alignment requirements */
|
||||
#define AL_CHAR 1
|
||||
#define AL_SHORT (int)SZ_SHORT
|
||||
#define AL_WORD (int)SZ_WORD
|
||||
#define AL_INT (int)SZ_WORD
|
||||
#define AL_LONG (int)SZ_WORD
|
||||
#define AL_FLOAT (int)SZ_WORD
|
||||
#define AL_DOUBLE (int)SZ_WORD
|
||||
#define AL_POINTER (int)SZ_WORD
|
||||
#define AL_STRUCT 1
|
||||
#define AL_UNION 1
|
||||
|
||||
|
||||
!File: debugcst.h
|
||||
#define DEBUG 1 /* perform various self-tests */
|
||||
|
||||
!File: inputtype.h
|
||||
#define INP_READ_IN_ONE 1 /* read input file in one */
|
||||
|
||||
|
||||
!File: maxset.h
|
||||
#define MAXSET 1024 /* maximum number of elements in a set,
|
||||
but what is a reasonable choice ???
|
||||
*/
|
||||
|
||||
!File: density.h
|
||||
#define DENSITY 3 /* see casestat.C for an explanation */
|
||||
54
lang/m2/comp/Resolve
Executable file
54
lang/m2/comp/Resolve
Executable file
@@ -0,0 +1,54 @@
|
||||
: create a directory Xsrc with name clashes resolved
|
||||
: and run make in that directory
|
||||
|
||||
case $# in
|
||||
1)
|
||||
;;
|
||||
*) echo "$0: one argument expected" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
currdir=`pwd`
|
||||
case $1 in
|
||||
main) target=$currdir/$1
|
||||
;;
|
||||
Xlint) target=$1
|
||||
;;
|
||||
*) echo "$0: $1: Illegal argument" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if test -d ../Xsrc
|
||||
then
|
||||
:
|
||||
else mkdir ../Xsrc
|
||||
fi
|
||||
make EMHOME=$EMHOME longnames
|
||||
: remove code generating routines from the clashes list as they are defines.
|
||||
: code generating routine names start with C_
|
||||
sed '/^C_/d' < longnames > tmp$$
|
||||
cclash -c -l7 tmp$$ > ../Xsrc/Xclashes
|
||||
rm -f tmp$$
|
||||
PW=`pwd`
|
||||
cd ../Xsrc
|
||||
if cmp -s Xclashes clashes
|
||||
then
|
||||
:
|
||||
else
|
||||
mv Xclashes clashes
|
||||
fi
|
||||
rm -f Makefile
|
||||
ed - $PW/Makefile <<'EOF'
|
||||
/^#EXCLEXCL/,/^#INCLINCL/d
|
||||
w Makefile
|
||||
q
|
||||
EOF
|
||||
for i in `cat $PW/Cfiles`
|
||||
do
|
||||
cat >> Makefile <<EOF
|
||||
|
||||
$i: clashes $PW/$i
|
||||
\$(CID) -Fclashes < $PW/$i > $i
|
||||
EOF
|
||||
done
|
||||
make EMHOME=$EMHOME CURRDIR=$currdir $target
|
||||
18
lang/m2/comp/SYSTEM.h
Normal file
18
lang/m2/comp/SYSTEM.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* S Y S T E M M O D U L E T E X T */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* Text of SYSTEM module, for as far as it can be expressed in Modula-2 */
|
||||
|
||||
#define SYSTEMTEXT "DEFINITION MODULE SYSTEM;\n\
|
||||
TYPE PROCESS = ADDRESS;\n\
|
||||
PROCEDURE NEWPROCESS(P:PROC; A:ADDRESS; n:CARDINAL; VAR p1:ADDRESS);\n\
|
||||
PROCEDURE TRANSFER(VAR p1,p2:ADDRESS);\n\
|
||||
END SYSTEM.\n"
|
||||
1
lang/m2/comp/Version.c
Normal file
1
lang/m2/comp/Version.c
Normal file
@@ -0,0 +1 @@
|
||||
static char Version[] = "ACK Modula-2 compiler Version 0.15";
|
||||
318
lang/m2/comp/casestat.C
Normal file
318
lang/m2/comp/casestat.C
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* C A S E S T A T E M E N T C O D E G E N E R A T I O N */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* Generation of case statements is done by first creating a
|
||||
description structure for the statement, build a list of the
|
||||
case-labels, then generating a case description in the code,
|
||||
and generating either CSA or CSB, and then generating code for the
|
||||
cases themselves.
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <em_label.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_code.h>
|
||||
#include <alloc.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "Lpars.h"
|
||||
#include "type.h"
|
||||
#include "LLlex.h"
|
||||
#include "node.h"
|
||||
#include "desig.h"
|
||||
#include "walk.h"
|
||||
#include "chk_expr.h"
|
||||
|
||||
#include "density.h"
|
||||
|
||||
struct switch_hdr {
|
||||
label sh_break; /* label of statement after this one */
|
||||
label sh_default; /* label of ELSE part, or 0 */
|
||||
int sh_nrofentries; /* number of cases */
|
||||
struct type *sh_type; /* type of case expression */
|
||||
arith sh_lowerbd; /* lowest case label */
|
||||
arith sh_upperbd; /* highest case label */
|
||||
struct case_entry *sh_entries; /* the cases with their generated
|
||||
labels
|
||||
*/
|
||||
};
|
||||
|
||||
/* STATICALLOCDEF "switch_hdr" 5 */
|
||||
|
||||
struct case_entry {
|
||||
struct case_entry *ce_next; /* next in list */
|
||||
label ce_label; /* generated label */
|
||||
arith ce_value; /* value of case label */
|
||||
};
|
||||
|
||||
/* STATICALLOCDEF "case_entry" 20 */
|
||||
|
||||
/* The constant DENSITY determines when CSA and when CSB instructions
|
||||
are generated. Reasonable values are: 2, 3, 4.
|
||||
On machines that have lots of address space and memory, higher values
|
||||
might also be reasonable. On these machines the density of jump tables
|
||||
may be lower.
|
||||
*/
|
||||
#define compact(nr, low, up) (nr != 0 && (up - low) / nr <= DENSITY)
|
||||
|
||||
CaseCode(nd, exitlabel)
|
||||
struct node *nd;
|
||||
label exitlabel;
|
||||
{
|
||||
/* Check the expression, stack a new case header and
|
||||
fill in the necessary fields.
|
||||
"exitlabel" is the exit-label of the closest enclosing
|
||||
LOOP-statement, or 0.
|
||||
*/
|
||||
register struct switch_hdr *sh = new_switch_hdr();
|
||||
register struct node *pnode = nd;
|
||||
register struct case_entry *ce;
|
||||
register arith val;
|
||||
label CaseDescrLab;
|
||||
int casecnt = 0;
|
||||
|
||||
assert(pnode->nd_class == Stat && pnode->nd_symb == CASE);
|
||||
|
||||
if (ChkExpression(pnode->nd_left)) {
|
||||
MkCoercion(&(pnode->nd_left),BaseType(pnode->nd_left->nd_type));
|
||||
CodePExpr(pnode->nd_left);
|
||||
}
|
||||
sh->sh_type = pnode->nd_left->nd_type;
|
||||
sh->sh_break = ++text_label;
|
||||
|
||||
/* Now, create case label list
|
||||
*/
|
||||
while (pnode = pnode->nd_right) {
|
||||
if (pnode->nd_class == Link && pnode->nd_symb == '|') {
|
||||
if (pnode->nd_left) {
|
||||
/* non-empty case
|
||||
*/
|
||||
pnode->nd_lab = ++text_label;
|
||||
casecnt++;
|
||||
if (! AddCases(sh, /* to descriptor */
|
||||
pnode->nd_left->nd_left,
|
||||
/* of case labels */
|
||||
pnode->nd_lab
|
||||
/* and code label */
|
||||
)) {
|
||||
FreeSh(sh);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Else part
|
||||
*/
|
||||
|
||||
sh->sh_default = ++text_label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!casecnt) {
|
||||
/* There were no cases, so we have to check the case-expression
|
||||
here
|
||||
*/
|
||||
if (! (sh->sh_type->tp_fund & T_DISCRETE)) {
|
||||
node_error(nd, "illegal type in CASE-expression");
|
||||
FreeSh(sh);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now generate code for the switch itself
|
||||
First the part that CSA and CSB descriptions have in common.
|
||||
*/
|
||||
CaseDescrLab = ++data_label; /* the rom must have a label */
|
||||
C_df_dlb(CaseDescrLab);
|
||||
if (sh->sh_default) C_rom_ilb(sh->sh_default);
|
||||
else C_rom_ucon("0", pointer_size);
|
||||
if (compact(sh->sh_nrofentries, sh->sh_lowerbd, sh->sh_upperbd)) {
|
||||
/* CSA
|
||||
*/
|
||||
C_rom_cst(sh->sh_lowerbd);
|
||||
C_rom_cst(sh->sh_upperbd - sh->sh_lowerbd);
|
||||
ce = sh->sh_entries;
|
||||
for (val = sh->sh_lowerbd; val <= sh->sh_upperbd; val++) {
|
||||
assert(ce);
|
||||
if (val == ce->ce_value) {
|
||||
C_rom_ilb(ce->ce_label);
|
||||
ce = ce->ce_next;
|
||||
}
|
||||
else if (sh->sh_default) C_rom_ilb(sh->sh_default);
|
||||
else C_rom_ucon("0", pointer_size);
|
||||
}
|
||||
C_lae_dlb(CaseDescrLab, (arith)0); /* perform the switch */
|
||||
C_csa(word_size);
|
||||
}
|
||||
else {
|
||||
/* CSB
|
||||
*/
|
||||
C_rom_cst((arith)sh->sh_nrofentries);
|
||||
for (ce = sh->sh_entries; ce; ce = ce->ce_next) {
|
||||
/* generate the entries: value + prog.label
|
||||
*/
|
||||
C_rom_cst(ce->ce_value);
|
||||
C_rom_ilb(ce->ce_label);
|
||||
}
|
||||
C_lae_dlb(CaseDescrLab, (arith)0); /* perform the switch */
|
||||
C_csb(word_size);
|
||||
}
|
||||
|
||||
/* Now generate code for the cases
|
||||
*/
|
||||
pnode = nd;
|
||||
while (pnode = pnode->nd_right) {
|
||||
if (pnode->nd_class == Link && pnode->nd_symb == '|') {
|
||||
if (pnode->nd_left) {
|
||||
C_df_ilb(pnode->nd_lab);
|
||||
WalkNode(pnode->nd_left->nd_right, exitlabel);
|
||||
C_bra(sh->sh_break);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Else part
|
||||
*/
|
||||
assert(sh->sh_default != 0);
|
||||
|
||||
C_df_ilb(sh->sh_default);
|
||||
WalkNode(pnode, exitlabel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
C_df_ilb(sh->sh_break);
|
||||
FreeSh(sh);
|
||||
}
|
||||
|
||||
FreeSh(sh)
|
||||
register struct switch_hdr *sh;
|
||||
{
|
||||
/* free the allocated switch structure
|
||||
*/
|
||||
register struct case_entry *ce;
|
||||
|
||||
ce = sh->sh_entries;
|
||||
while (ce) {
|
||||
struct case_entry *tmp = ce->ce_next;
|
||||
|
||||
free_case_entry(ce);
|
||||
ce = tmp;
|
||||
}
|
||||
|
||||
free_switch_hdr(sh);
|
||||
}
|
||||
|
||||
AddCases(sh, node, lbl)
|
||||
struct switch_hdr *sh;
|
||||
register struct node *node;
|
||||
label lbl;
|
||||
{
|
||||
/* Add case labels to the case label list
|
||||
*/
|
||||
register arith v1, v2;
|
||||
|
||||
if (node->nd_class == Link) {
|
||||
if (node->nd_symb == UPTO) {
|
||||
assert(node->nd_left->nd_class == Value);
|
||||
assert(node->nd_right->nd_class == Value);
|
||||
|
||||
v2 = node->nd_right->nd_INT;
|
||||
node->nd_type = node->nd_left->nd_type;
|
||||
for (v1 = node->nd_left->nd_INT; v1 <= v2; v1++) {
|
||||
node->nd_INT = v1;
|
||||
if (! AddOneCase(sh, node, lbl)) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(node->nd_symb == ',');
|
||||
return AddCases(sh, node->nd_left, lbl) &&
|
||||
AddCases(sh, node->nd_right, lbl);
|
||||
}
|
||||
|
||||
assert(node->nd_class == Value);
|
||||
return AddOneCase(sh, node, lbl);
|
||||
}
|
||||
|
||||
AddOneCase(sh, node, lbl)
|
||||
register struct switch_hdr *sh;
|
||||
struct node *node;
|
||||
label lbl;
|
||||
{
|
||||
register struct case_entry *ce = new_case_entry();
|
||||
register struct case_entry *c1 = sh->sh_entries, *c2 = 0;
|
||||
|
||||
ce->ce_label = lbl;
|
||||
ce->ce_value = node->nd_INT;
|
||||
if (! ChkCompat(&node, sh->sh_type, "case")) {
|
||||
free_case_entry(ce);
|
||||
return 0;
|
||||
}
|
||||
if (sh->sh_entries == 0) {
|
||||
/* first case entry
|
||||
*/
|
||||
ce->ce_next = (struct case_entry *) 0;
|
||||
sh->sh_entries = ce;
|
||||
sh->sh_lowerbd = sh->sh_upperbd = ce->ce_value;
|
||||
sh->sh_nrofentries = 1;
|
||||
}
|
||||
else {
|
||||
/* second etc. case entry
|
||||
find the proper place to put ce into the list
|
||||
*/
|
||||
|
||||
if (ce->ce_value < sh->sh_lowerbd) {
|
||||
sh->sh_lowerbd = ce->ce_value;
|
||||
}
|
||||
else if (ce->ce_value > sh->sh_upperbd) {
|
||||
sh->sh_upperbd = ce->ce_value;
|
||||
}
|
||||
while (c1 && c1->ce_value < ce->ce_value) {
|
||||
c2 = c1;
|
||||
c1 = c1->ce_next;
|
||||
}
|
||||
/* At this point three cases are possible:
|
||||
1: c1 != 0 && c2 != 0:
|
||||
insert ce somewhere in the middle
|
||||
2: c1 != 0 && c2 == 0:
|
||||
insert ce right after the head
|
||||
3: c1 == 0 && c2 != 0:
|
||||
append ce to last element
|
||||
The case c1 == 0 && c2 == 0 cannot occur, since
|
||||
the list is guaranteed not to be empty.
|
||||
*/
|
||||
if (c1) {
|
||||
if (c1->ce_value == ce->ce_value) {
|
||||
node_error(node, "multiple case entry for value %ld", ce->ce_value);
|
||||
free_case_entry(ce);
|
||||
return 0;
|
||||
}
|
||||
if (c2) {
|
||||
ce->ce_next = c2->ce_next;
|
||||
c2->ce_next = ce;
|
||||
}
|
||||
else {
|
||||
ce->ce_next = sh->sh_entries;
|
||||
sh->sh_entries = ce;
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(c2);
|
||||
|
||||
ce->ce_next = (struct case_entry *) 0;
|
||||
c2->ce_next = ce;
|
||||
}
|
||||
(sh->sh_nrofentries)++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
54
lang/m2/comp/char.tab
Normal file
54
lang/m2/comp/char.tab
Normal file
@@ -0,0 +1,54 @@
|
||||
% character tables for mod2 compiler
|
||||
% $Header$
|
||||
%S129
|
||||
%F %s,
|
||||
%
|
||||
% CHARACTER CLASSES
|
||||
%
|
||||
%C
|
||||
STGARB:\000-\200
|
||||
STSKIP: \r\t
|
||||
STNL:\012\013\014
|
||||
STSIMP:#&()*+,-/;=[]^{|}~
|
||||
STCOMP:.:<>
|
||||
STIDF:a-zA-Z
|
||||
STSTR:"'
|
||||
STNUM:0-9
|
||||
STEOI:\200
|
||||
%T#include "class.h"
|
||||
%Tchar tkclass[] = {
|
||||
%p
|
||||
%T};
|
||||
%
|
||||
% INIDF
|
||||
%
|
||||
%C
|
||||
1:a-zA-Z0-9
|
||||
%Tchar inidf[] = {
|
||||
%F %s,
|
||||
%p
|
||||
%T};
|
||||
%
|
||||
% ISDIG
|
||||
%
|
||||
%C
|
||||
1:0-9
|
||||
%Tchar isdig[] = {
|
||||
%p
|
||||
%T};
|
||||
%
|
||||
% ISHEX
|
||||
%
|
||||
%C
|
||||
1:a-fA-F
|
||||
%Tchar ishex[] = {
|
||||
%p
|
||||
%T};
|
||||
%
|
||||
% ISOCT
|
||||
%
|
||||
%C
|
||||
1:0-7
|
||||
%Tchar isoct[] = {
|
||||
%p
|
||||
%T};
|
||||
1328
lang/m2/comp/chk_expr.c
Normal file
1328
lang/m2/comp/chk_expr.c
Normal file
File diff suppressed because it is too large
Load Diff
20
lang/m2/comp/chk_expr.h
Normal file
20
lang/m2/comp/chk_expr.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* E X P R E S S I O N C H E C K I N G */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
extern int (*ExprChkTable[])(); /* table of expression checking
|
||||
functions, indexed by node class
|
||||
*/
|
||||
extern int (*DesigChkTable[])(); /* table of designator checking
|
||||
functions, indexed by node class
|
||||
*/
|
||||
|
||||
#define ChkExpression(expp) ((*ExprChkTable[(expp)->nd_class])(expp))
|
||||
#define ChkDesignator(expp) ((*DesigChkTable[(expp)->nd_class])(expp))
|
||||
45
lang/m2/comp/class.h
Normal file
45
lang/m2/comp/class.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* U S E O F C H A R A C T E R C L A S S E S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* As a starter, chars are divided into classes, according to which
|
||||
token they can be the start of.
|
||||
At present such a class number is supposed to fit in 4 bits.
|
||||
*/
|
||||
|
||||
#define class(ch) (tkclass[ch])
|
||||
|
||||
/* Being the start of a token is, fortunately, a mutual exclusive
|
||||
property, so, as there are less than 16 classes they can be
|
||||
packed in 4 bits.
|
||||
*/
|
||||
|
||||
#define STSKIP 0 /* spaces and so on: skipped characters */
|
||||
#define STNL 1 /* newline character(s): update linenumber etc. */
|
||||
#define STGARB 2 /* garbage ascii character: not allowed */
|
||||
#define STSIMP 3 /* this character can occur as token */
|
||||
#define STCOMP 4 /* this one can start a compound token */
|
||||
#define STIDF 5 /* being the initial character of an identifier */
|
||||
#define STCHAR 6 /* the starter of a character constant */
|
||||
#define STSTR 7 /* the starter of a string */
|
||||
#define STNUM 8 /* the starter of a numeric constant */
|
||||
#define STEOI 9 /* End-Of-Information mark */
|
||||
|
||||
/* But occurring inside a token is not, so we need 1 bit for each
|
||||
class. This is implemented as a collection of tables to speed up
|
||||
the decision whether a character has a special meaning.
|
||||
*/
|
||||
#define in_idf(ch) ((unsigned)ch < 0177 && inidf[ch])
|
||||
#define is_oct(ch) ((unsigned)ch < 0177 && isoct[ch])
|
||||
#define is_dig(ch) ((unsigned)ch < 0177 && isdig[ch])
|
||||
#define is_hex(ch) ((unsigned)ch < 0177 && ishex[ch])
|
||||
|
||||
extern char tkclass[];
|
||||
extern char inidf[], isoct[], isdig[], ishex[];
|
||||
1055
lang/m2/comp/code.c
Normal file
1055
lang/m2/comp/code.c
Normal file
File diff suppressed because it is too large
Load Diff
21
lang/m2/comp/const.h
Normal file
21
lang/m2/comp/const.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* C O N S T A N T S F O R E X P R E S S I O N H A N D L I N G */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
extern long
|
||||
mach_long_sign; /* sign bit of the machine long */
|
||||
extern int
|
||||
mach_long_size; /* size of long on this machine == sizeof(long) */
|
||||
extern arith
|
||||
max_int, /* maximum integer on target machine */
|
||||
max_unsigned, /* maximum unsigned on target machine */
|
||||
max_longint; /* maximum longint on target machine */
|
||||
extern unsigned int
|
||||
wrd_bits; /* Number of bits in a word */
|
||||
496
lang/m2/comp/cstoper.c
Normal file
496
lang/m2/comp/cstoper.c
Normal file
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* C O N S T A N T E X P R E S S I O N H A N D L I N G */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "debug.h"
|
||||
#include "target_sizes.h"
|
||||
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "idf.h"
|
||||
#include "type.h"
|
||||
#include "LLlex.h"
|
||||
#include "node.h"
|
||||
#include "Lpars.h"
|
||||
#include "standards.h"
|
||||
#include "warning.h"
|
||||
|
||||
long mach_long_sign; /* sign bit of the machine long */
|
||||
int mach_long_size; /* size of long on this machine == sizeof(long) */
|
||||
long full_mask[MAXSIZE];/* full_mask[1] == 0xFF, full_mask[2] == 0xFFFF, .. */
|
||||
long int_mask[MAXSIZE]; /* int_mask[1] == 0x7F, int_mask[2] == 0x7FFF, .. */
|
||||
arith max_int; /* maximum integer on target machine */
|
||||
arith max_unsigned; /* maximum unsigned on target machine */
|
||||
arith max_longint; /* maximum longint on target machine */
|
||||
unsigned int wrd_bits; /* number of bits in a word */
|
||||
|
||||
extern char options[];
|
||||
|
||||
static char ovflow[] = "overflow in constant expression";
|
||||
|
||||
cstunary(expp)
|
||||
register struct node *expp;
|
||||
{
|
||||
/* The unary operation in "expp" is performed on the constant
|
||||
expression below it, and the result restored in expp.
|
||||
*/
|
||||
register struct node *right = expp->nd_right;
|
||||
|
||||
switch(expp->nd_symb) {
|
||||
/* Should not get here
|
||||
case '+':
|
||||
break;
|
||||
*/
|
||||
|
||||
case '-':
|
||||
expp->nd_INT = -right->nd_INT;
|
||||
if (expp->nd_type->tp_fund == T_INTORCARD) {
|
||||
expp->nd_type = int_type;
|
||||
}
|
||||
break;
|
||||
|
||||
case NOT:
|
||||
case '~':
|
||||
expp->nd_INT = !right->nd_INT;
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(cstunary)");
|
||||
}
|
||||
|
||||
expp->nd_class = Value;
|
||||
expp->nd_symb = right->nd_symb;
|
||||
CutSize(expp);
|
||||
FreeNode(right);
|
||||
expp->nd_right = 0;
|
||||
}
|
||||
|
||||
cstbin(expp)
|
||||
register struct node *expp;
|
||||
{
|
||||
/* The binary operation in "expp" is performed on the constant
|
||||
expressions below it, and the result restored in
|
||||
expp.
|
||||
*/
|
||||
register arith o1 = expp->nd_left->nd_INT;
|
||||
register arith o2 = expp->nd_right->nd_INT;
|
||||
register int uns = expp->nd_left->nd_type != int_type;
|
||||
|
||||
assert(expp->nd_class == Oper);
|
||||
assert(expp->nd_left->nd_class == Value);
|
||||
assert(expp->nd_right->nd_class == Value);
|
||||
|
||||
switch (expp->nd_symb) {
|
||||
case '*':
|
||||
o1 *= o2;
|
||||
break;
|
||||
|
||||
case DIV:
|
||||
if (o2 == 0) {
|
||||
node_error(expp, "division by 0");
|
||||
return;
|
||||
}
|
||||
if (uns) {
|
||||
/* this is more of a problem than you might
|
||||
think on C compilers which do not have
|
||||
unsigned long.
|
||||
*/
|
||||
if (o2 & mach_long_sign) {/* o2 > max_long */
|
||||
o1 = ! (o1 >= 0 || o1 < o2);
|
||||
/* this is the unsigned test
|
||||
o1 < o2 for o2 > max_long
|
||||
*/
|
||||
}
|
||||
else { /* o2 <= max_long */
|
||||
long half, bit, hdiv, hrem, rem;
|
||||
|
||||
half = (o1 >> 1) & ~mach_long_sign;
|
||||
bit = o1 & 01;
|
||||
/* now o1 == 2 * half + bit
|
||||
and half <= max_long
|
||||
and bit <= max_long
|
||||
*/
|
||||
hdiv = half / o2;
|
||||
hrem = half % o2;
|
||||
rem = 2 * hrem + bit;
|
||||
o1 = 2 * hdiv + (rem < 0 || rem >= o2);
|
||||
/* that is the unsigned compare
|
||||
rem >= o2 for o2 <= max_long
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
o1 /= o2;
|
||||
break;
|
||||
|
||||
case MOD:
|
||||
if (o2 == 0) {
|
||||
node_error(expp, "modulo by 0");
|
||||
return;
|
||||
}
|
||||
if (uns) {
|
||||
if (o2 & mach_long_sign) {/* o2 > max_long */
|
||||
o1 = (o1 >= 0 || o1 < o2) ? o1 : o1 - o2;
|
||||
/* this is the unsigned test
|
||||
o1 < o2 for o2 > max_long
|
||||
*/
|
||||
}
|
||||
else { /* o2 <= max_long */
|
||||
long half, bit, hrem, rem;
|
||||
|
||||
half = (o1 >> 1) & ~mach_long_sign;
|
||||
bit = o1 & 01;
|
||||
/* now o1 == 2 * half + bit
|
||||
and half <= max_long
|
||||
and bit <= max_long
|
||||
*/
|
||||
hrem = half % o2;
|
||||
rem = 2 * hrem + bit;
|
||||
o1 = (rem < 0 || rem >= o2) ? rem - o2 : rem;
|
||||
}
|
||||
}
|
||||
else
|
||||
o1 %= o2;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
o1 += o2;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
o1 -= o2;
|
||||
if (expp->nd_type->tp_fund == T_INTORCARD) {
|
||||
if (o1 < 0) expp->nd_type = int_type;
|
||||
}
|
||||
break;
|
||||
|
||||
case '<':
|
||||
{ arith tmp = o1;
|
||||
|
||||
o1 = o2;
|
||||
o2 = tmp;
|
||||
}
|
||||
/* Fall through */
|
||||
|
||||
case '>':
|
||||
if (uns) {
|
||||
o1 = (o1 & mach_long_sign ?
|
||||
(o2 & mach_long_sign ? o1 > o2 : 1) :
|
||||
(o2 & mach_long_sign ? 0 : o1 > o2)
|
||||
);
|
||||
}
|
||||
else
|
||||
o1 = (o1 > o2);
|
||||
break;
|
||||
|
||||
case LESSEQUAL:
|
||||
{ arith tmp = o1;
|
||||
|
||||
o1 = o2;
|
||||
o2 = tmp;
|
||||
}
|
||||
/* Fall through */
|
||||
|
||||
case GREATEREQUAL:
|
||||
o1 = chk_bounds(o2, o1, uns ? T_CARDINAL : T_INTEGER);
|
||||
break;
|
||||
|
||||
case '=':
|
||||
o1 = (o1 == o2);
|
||||
break;
|
||||
|
||||
case '#':
|
||||
o1 = (o1 != o2);
|
||||
break;
|
||||
|
||||
case AND:
|
||||
case '&':
|
||||
o1 = (o1 && o2);
|
||||
break;
|
||||
|
||||
case OR:
|
||||
o1 = (o1 || o2);
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(cstbin)");
|
||||
}
|
||||
|
||||
expp->nd_class = Value;
|
||||
expp->nd_token = expp->nd_right->nd_token;
|
||||
if (expp->nd_type == bool_type) expp->nd_symb = INTEGER;
|
||||
expp->nd_INT = o1;
|
||||
CutSize(expp);
|
||||
FreeNode(expp->nd_left);
|
||||
FreeNode(expp->nd_right);
|
||||
expp->nd_left = expp->nd_right = 0;
|
||||
}
|
||||
|
||||
cstset(expp)
|
||||
register struct node *expp;
|
||||
{
|
||||
register arith *set1, *set2;
|
||||
arith *resultset = 0;
|
||||
register unsigned int setsize;
|
||||
register int j;
|
||||
|
||||
assert(expp->nd_right->nd_class == Set);
|
||||
assert(expp->nd_symb == IN || expp->nd_left->nd_class == Set);
|
||||
|
||||
set2 = expp->nd_right->nd_set;
|
||||
setsize = (unsigned) expp->nd_right->nd_type->tp_size / (unsigned) word_size;
|
||||
|
||||
if (expp->nd_symb == IN) {
|
||||
unsigned i;
|
||||
|
||||
assert(expp->nd_left->nd_class == Value);
|
||||
|
||||
i = expp->nd_left->nd_INT;
|
||||
expp->nd_class = Value;
|
||||
expp->nd_INT = (expp->nd_left->nd_INT >= 0 &&
|
||||
expp->nd_left->nd_INT < setsize * wrd_bits &&
|
||||
(set2[i / wrd_bits] & (1 << (i % wrd_bits))));
|
||||
free((char *) set2);
|
||||
expp->nd_symb = INTEGER;
|
||||
}
|
||||
else {
|
||||
set1 = expp->nd_left->nd_set;
|
||||
resultset = set1;
|
||||
expp->nd_left->nd_set = 0;
|
||||
switch(expp->nd_symb) {
|
||||
case '+':
|
||||
/* Set union
|
||||
*/
|
||||
for (j = 0; j < setsize; j++) {
|
||||
*set1++ |= *set2++;
|
||||
}
|
||||
break;
|
||||
|
||||
case '-':
|
||||
/* Set difference
|
||||
*/
|
||||
for (j = 0; j < setsize; j++) {
|
||||
*set1++ &= ~*set2++;
|
||||
}
|
||||
break;
|
||||
|
||||
case '*':
|
||||
/* Set intersection
|
||||
*/
|
||||
for (j = 0; j < setsize; j++) {
|
||||
*set1++ &= *set2++;
|
||||
}
|
||||
break;
|
||||
|
||||
case '/':
|
||||
/* Symmetric set difference
|
||||
*/
|
||||
for (j = 0; j < setsize; j++) {
|
||||
*set1++ ^= *set2++;
|
||||
}
|
||||
break;
|
||||
|
||||
case GREATEREQUAL:
|
||||
case LESSEQUAL:
|
||||
case '=':
|
||||
case '#':
|
||||
/* Constant set comparisons
|
||||
*/
|
||||
expp->nd_left->nd_set = set1; /* may be disposed of */
|
||||
for (j = 0; j < setsize; j++) {
|
||||
switch(expp->nd_symb) {
|
||||
case GREATEREQUAL:
|
||||
if ((*set1 | *set2++) != *set1) break;
|
||||
set1++;
|
||||
continue;
|
||||
case LESSEQUAL:
|
||||
if ((*set2 | *set1++) != *set2) break;
|
||||
set2++;
|
||||
continue;
|
||||
case '=':
|
||||
case '#':
|
||||
if (*set1++ != *set2++) break;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (j < setsize) {
|
||||
expp->nd_INT = expp->nd_symb == '#';
|
||||
}
|
||||
else {
|
||||
expp->nd_INT = expp->nd_symb != '#';
|
||||
}
|
||||
expp->nd_class = Value;
|
||||
expp->nd_symb = INTEGER;
|
||||
freesets(expp);
|
||||
return;
|
||||
default:
|
||||
crash("(cstset)");
|
||||
}
|
||||
freesets(expp);
|
||||
expp->nd_class = Set;
|
||||
expp->nd_set = resultset;
|
||||
return;
|
||||
}
|
||||
FreeNode(expp->nd_left);
|
||||
FreeNode(expp->nd_right);
|
||||
expp->nd_left = expp->nd_right = 0;
|
||||
}
|
||||
|
||||
freesets(expp)
|
||||
register struct node *expp;
|
||||
{
|
||||
if (expp->nd_right->nd_set) {
|
||||
free((char *) expp->nd_right->nd_set);
|
||||
}
|
||||
if (expp->nd_left->nd_set) {
|
||||
free((char *) expp->nd_left->nd_set);
|
||||
}
|
||||
FreeNode(expp->nd_left);
|
||||
FreeNode(expp->nd_right);
|
||||
expp->nd_left = expp->nd_right = 0;
|
||||
}
|
||||
|
||||
cstcall(expp, call)
|
||||
register struct node *expp;
|
||||
{
|
||||
/* a standard procedure call is found that can be evaluated
|
||||
compile time, so do so.
|
||||
*/
|
||||
register struct node *expr = 0;
|
||||
|
||||
assert(expp->nd_class == Call);
|
||||
|
||||
if (expp->nd_right) {
|
||||
expr = expp->nd_right->nd_left;
|
||||
expp->nd_right->nd_left = 0;
|
||||
FreeNode(expp->nd_right);
|
||||
}
|
||||
|
||||
expp->nd_class = Value;
|
||||
expp->nd_symb = INTEGER;
|
||||
switch(call) {
|
||||
case S_ABS:
|
||||
if (expr->nd_INT < 0) expp->nd_INT = - expr->nd_INT;
|
||||
else expp->nd_INT = expr->nd_INT;
|
||||
CutSize(expp);
|
||||
break;
|
||||
|
||||
case S_CAP:
|
||||
if (expr->nd_INT >= 'a' && expr->nd_INT <= 'z') {
|
||||
expr->nd_INT = expr->nd_INT + ('A' - 'a');
|
||||
}
|
||||
expp->nd_INT = expr->nd_INT;
|
||||
break;
|
||||
|
||||
case S_MAX:
|
||||
if (expp->nd_type == int_type) {
|
||||
expp->nd_INT = max_int;
|
||||
}
|
||||
else if (expp->nd_type == longint_type) {
|
||||
expp->nd_INT = max_longint;
|
||||
}
|
||||
else if (expp->nd_type == card_type) {
|
||||
expp->nd_INT = max_unsigned;
|
||||
}
|
||||
else if (expp->nd_type->tp_fund == T_SUBRANGE) {
|
||||
expp->nd_INT = expp->nd_type->sub_ub;
|
||||
}
|
||||
else expp->nd_INT = expp->nd_type->enm_ncst - 1;
|
||||
break;
|
||||
|
||||
case S_MIN:
|
||||
if (expp->nd_type == int_type) {
|
||||
expp->nd_INT = -max_int;
|
||||
if (! options['s']) expp->nd_INT--;
|
||||
}
|
||||
else if (expp->nd_type == longint_type) {
|
||||
expp->nd_INT = - max_longint;
|
||||
if (! options['s']) expp->nd_INT--;
|
||||
}
|
||||
else if (expp->nd_type->tp_fund == T_SUBRANGE) {
|
||||
expp->nd_INT = expp->nd_type->sub_lb;
|
||||
}
|
||||
else expp->nd_INT = 0;
|
||||
break;
|
||||
|
||||
case S_ODD:
|
||||
expp->nd_INT = (expr->nd_INT & 1);
|
||||
break;
|
||||
|
||||
case S_SIZE:
|
||||
expp->nd_INT = expr->nd_type->tp_size;
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(cstcall)");
|
||||
}
|
||||
FreeNode(expr);
|
||||
FreeNode(expp->nd_left);
|
||||
expp->nd_right = expp->nd_left = 0;
|
||||
}
|
||||
|
||||
CutSize(expr)
|
||||
register struct node *expr;
|
||||
{
|
||||
/* The constant value of the expression expr is made to
|
||||
conform to the size of the type of the expression.
|
||||
*/
|
||||
register arith o1 = expr->nd_INT;
|
||||
register struct type *tp = BaseType(expr->nd_type);
|
||||
int uns;
|
||||
int size = tp->tp_size;
|
||||
|
||||
assert(expr->nd_class == Value);
|
||||
uns = (tp->tp_fund & (T_CARDINAL|T_CHAR));
|
||||
if (uns) {
|
||||
if (o1 & ~full_mask[size]) {
|
||||
node_warning(expr, W_ORDINARY, ovflow);
|
||||
o1 &= full_mask[size];
|
||||
}
|
||||
}
|
||||
else {
|
||||
int nbits = (int) (mach_long_size - size) * 8;
|
||||
long remainder = o1 & ~int_mask[size];
|
||||
|
||||
if (remainder != 0 && remainder != ~int_mask[size]) {
|
||||
node_warning(expr, W_ORDINARY, ovflow);
|
||||
o1 <<= nbits;
|
||||
o1 >>= nbits;
|
||||
}
|
||||
}
|
||||
expr->nd_INT = o1;
|
||||
}
|
||||
|
||||
InitCst()
|
||||
{
|
||||
register int i = 0;
|
||||
register arith bt = (arith)0;
|
||||
|
||||
while (!(bt < 0)) {
|
||||
bt = (bt << 8) + 0377, i++;
|
||||
if (i == MAXSIZE)
|
||||
fatal("array full_mask too small for this machine");
|
||||
full_mask[i] = bt;
|
||||
int_mask[i] = bt & ~(1L << ((i << 3) - 1));
|
||||
}
|
||||
mach_long_size = i;
|
||||
mach_long_sign = 1L << (mach_long_size * 8 - 1);
|
||||
if (long_size > mach_long_size) {
|
||||
fatal("sizeof (long) insufficient on this machine");
|
||||
}
|
||||
|
||||
max_int = int_mask[int_size];
|
||||
max_unsigned = full_mask[int_size];
|
||||
max_longint = int_mask[long_size];
|
||||
wrd_bits = 8 * (unsigned) word_size;
|
||||
}
|
||||
18
lang/m2/comp/debug.h
Normal file
18
lang/m2/comp/debug.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* D E B U G G I N G M A C R O */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "debugcst.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DO_DEBUG(x, y) ((x) && (y))
|
||||
#else
|
||||
#define DO_DEBUG(x, y)
|
||||
#endif
|
||||
529
lang/m2/comp/declar.g
Normal file
529
lang/m2/comp/declar.g
Normal file
@@ -0,0 +1,529 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* D E C L A R A T I O N S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
{
|
||||
#include "debug.h"
|
||||
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <alloc.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "idf.h"
|
||||
#include "LLlex.h"
|
||||
#include "def.h"
|
||||
#include "type.h"
|
||||
#include "scope.h"
|
||||
#include "node.h"
|
||||
#include "misc.h"
|
||||
#include "main.h"
|
||||
#include "chk_expr.h"
|
||||
#include "warning.h"
|
||||
|
||||
int proclevel = 0; /* nesting level of procedures */
|
||||
int return_occurred; /* set if a return occurs in a block */
|
||||
|
||||
#define needs_static_link() (proclevel > 1)
|
||||
extern struct node *EmptyStatement;
|
||||
}
|
||||
|
||||
/* inline in declaration: need space
|
||||
ProcedureDeclaration
|
||||
{
|
||||
struct def *df;
|
||||
} :
|
||||
{ ++proclevel; }
|
||||
ProcedureHeading(&df, D_PROCEDURE)
|
||||
';' block(&(df->prc_body))
|
||||
IDENT
|
||||
{ EndProc(df, dot.TOK_IDF);
|
||||
--proclevel;
|
||||
}
|
||||
;
|
||||
*/
|
||||
|
||||
ProcedureHeading(struct def **pdf; int type;)
|
||||
{
|
||||
struct type *tp = 0;
|
||||
arith parmaddr = needs_static_link() ? pointer_size : 0;
|
||||
struct paramlist *pr = 0;
|
||||
} :
|
||||
PROCEDURE IDENT
|
||||
{ *pdf = DeclProc(type, dot.TOK_IDF); }
|
||||
[
|
||||
'('
|
||||
[
|
||||
FPSection(&pr, &parmaddr)
|
||||
[
|
||||
';' FPSection(&pr, &parmaddr)
|
||||
]*
|
||||
]?
|
||||
')'
|
||||
[ ':' qualtype(&tp)
|
||||
]?
|
||||
]?
|
||||
{ CheckWithDef(*pdf, proc_type(tp, pr, parmaddr));
|
||||
if (tp && IsConstructed(tp)) {
|
||||
warning(W_STRICT, "procedure \"%s\" has a constructed result type",
|
||||
(*pdf)->df_idf->id_text);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
block(struct node **pnd;) :
|
||||
[ %persistent
|
||||
declaration
|
||||
]*
|
||||
{ return_occurred = 0; }
|
||||
[ %default
|
||||
BEGIN
|
||||
StatementSequence(pnd)
|
||||
|
|
||||
{ *pnd = EmptyStatement; }
|
||||
]
|
||||
END
|
||||
;
|
||||
|
||||
declaration
|
||||
{
|
||||
struct def *df;
|
||||
} :
|
||||
CONST [ ConstantDeclaration ';' ]*
|
||||
|
|
||||
TYPE [ TypeDeclaration ';' ]*
|
||||
|
|
||||
VAR [ VariableDeclaration ';' ]*
|
||||
|
|
||||
{ ++proclevel; }
|
||||
ProcedureHeading(&df, D_PROCEDURE)
|
||||
';'
|
||||
block(&(df->prc_body))
|
||||
IDENT
|
||||
{ EndProc(df, dot.TOK_IDF);
|
||||
--proclevel;
|
||||
}
|
||||
';'
|
||||
|
|
||||
ModuleDeclaration ';'
|
||||
;
|
||||
|
||||
/* inline in procedureheading: need space
|
||||
FormalParameters(struct paramlist **ppr; arith *parmaddr; struct type **ptp;):
|
||||
'('
|
||||
[
|
||||
FPSection(ppr, parmaddr)
|
||||
[
|
||||
';' FPSection(ppr, parmaddr)
|
||||
]*
|
||||
]?
|
||||
')'
|
||||
[ ':' qualtype(ptp)
|
||||
]?
|
||||
;
|
||||
*/
|
||||
|
||||
FPSection(struct paramlist **ppr; arith *parmaddr;)
|
||||
{
|
||||
struct node *FPList;
|
||||
struct type *tp;
|
||||
int VARp;
|
||||
} :
|
||||
var(&VARp) IdentList(&FPList) ':' FormalType(&tp)
|
||||
{ EnterParamList(ppr, FPList, tp, VARp, parmaddr); }
|
||||
;
|
||||
|
||||
FormalType(struct type **ptp;)
|
||||
{
|
||||
extern arith ArrayElSize();
|
||||
} :
|
||||
ARRAY OF qualtype(ptp)
|
||||
{ /* index type of conformant array is "CARDINAL".
|
||||
Recognize a conformant array by size 0.
|
||||
*/
|
||||
register struct type *tp = construct_type(T_ARRAY, card_type);
|
||||
|
||||
tp->arr_elem = *ptp;
|
||||
*ptp = tp;
|
||||
tp->arr_elsize = ArrayElSize(tp->arr_elem);
|
||||
tp->tp_align = tp->arr_elem->tp_align;
|
||||
}
|
||||
|
|
||||
qualtype(ptp)
|
||||
;
|
||||
|
||||
TypeDeclaration
|
||||
{
|
||||
struct def *df;
|
||||
struct type *tp;
|
||||
register struct node *nd;
|
||||
}:
|
||||
IDENT { df = define(dot.TOK_IDF, CurrentScope, D_TYPE);
|
||||
nd = dot2leaf(Name);
|
||||
}
|
||||
'=' type(&tp)
|
||||
{ DeclareType(nd, df, tp);
|
||||
free_node(nd);
|
||||
}
|
||||
;
|
||||
|
||||
type(register struct type **ptp;):
|
||||
%default SimpleType(ptp)
|
||||
|
|
||||
ArrayType(ptp)
|
||||
|
|
||||
RecordType(ptp)
|
||||
|
|
||||
SetType(ptp)
|
||||
|
|
||||
PointerType(ptp)
|
||||
|
|
||||
ProcedureType(ptp)
|
||||
;
|
||||
|
||||
SimpleType(register struct type **ptp;)
|
||||
{
|
||||
struct type *tp;
|
||||
} :
|
||||
qualtype(ptp)
|
||||
[
|
||||
/* nothing */
|
||||
|
|
||||
SubrangeType(&tp)
|
||||
/* The subrange type is given a base type by the
|
||||
qualident (this is new modula-2).
|
||||
*/
|
||||
{ chk_basesubrange(tp, *ptp); *ptp = tp; }
|
||||
]
|
||||
|
|
||||
enumeration(ptp)
|
||||
|
|
||||
SubrangeType(ptp)
|
||||
;
|
||||
|
||||
enumeration(struct type **ptp;)
|
||||
{
|
||||
struct node *EnumList;
|
||||
} :
|
||||
'(' IdentList(&EnumList) ')'
|
||||
{ *ptp = enum_type(EnumList); }
|
||||
;
|
||||
|
||||
IdentList(struct node **p;)
|
||||
{
|
||||
register struct node *q;
|
||||
} :
|
||||
IDENT { *p = q = dot2leaf(Value); }
|
||||
[ %persistent
|
||||
',' IDENT
|
||||
{ q->nd_left = dot2leaf(Value);
|
||||
q = q->nd_left;
|
||||
}
|
||||
]*
|
||||
{ q->nd_left = 0; }
|
||||
;
|
||||
|
||||
SubrangeType(struct type **ptp;)
|
||||
{
|
||||
struct node *nd1, *nd2;
|
||||
}:
|
||||
/*
|
||||
This is not exactly the rule in the new report, but see
|
||||
the rule for "SimpleType".
|
||||
*/
|
||||
'[' ConstExpression(&nd1)
|
||||
UPTO ConstExpression(&nd2)
|
||||
']'
|
||||
{ *ptp = subr_type(nd1, nd2);
|
||||
free_node(nd1);
|
||||
free_node(nd2);
|
||||
}
|
||||
;
|
||||
|
||||
ArrayType(struct type **ptp;)
|
||||
{
|
||||
struct type *tp;
|
||||
register struct type *tp2;
|
||||
} :
|
||||
ARRAY SimpleType(&tp)
|
||||
{ *ptp = tp2 = construct_type(T_ARRAY, tp); }
|
||||
[
|
||||
',' SimpleType(&tp)
|
||||
{ tp2->arr_elem = construct_type(T_ARRAY, tp);
|
||||
tp2 = tp2->arr_elem;
|
||||
}
|
||||
]* OF type(&tp)
|
||||
{ tp2->arr_elem = tp;
|
||||
ArraySizes(*ptp);
|
||||
}
|
||||
;
|
||||
|
||||
RecordType(struct type **ptp;)
|
||||
{
|
||||
register struct scope *scope;
|
||||
arith size = 0;
|
||||
int xalign = struct_align;
|
||||
}
|
||||
:
|
||||
RECORD
|
||||
{ scope = open_and_close_scope(OPENSCOPE); }
|
||||
FieldListSequence(scope, &size, &xalign)
|
||||
{ if (size == 0) {
|
||||
warning(W_ORDINARY, "empty record declaration");
|
||||
size = 1;
|
||||
}
|
||||
*ptp = standard_type(T_RECORD, xalign, size);
|
||||
(*ptp)->rec_scope = scope;
|
||||
}
|
||||
END
|
||||
;
|
||||
|
||||
FieldListSequence(struct scope *scope; arith *cnt; int *palign;):
|
||||
FieldList(scope, cnt, palign)
|
||||
[
|
||||
';' FieldList(scope, cnt, palign)
|
||||
]*
|
||||
;
|
||||
|
||||
FieldList(struct scope *scope; arith *cnt; int *palign;)
|
||||
{
|
||||
struct node *FldList;
|
||||
struct type *tp;
|
||||
struct node *nd;
|
||||
register struct def *df;
|
||||
arith tcnt, max;
|
||||
} :
|
||||
[
|
||||
IdentList(&FldList) ':' type(&tp)
|
||||
{
|
||||
*palign = lcm(*palign, tp->tp_align);
|
||||
EnterFieldList(FldList, tp, scope, cnt);
|
||||
}
|
||||
|
|
||||
CASE
|
||||
/* Also accept old fashioned Modula-2 syntax, but give a warning.
|
||||
Sorry for the complicated code.
|
||||
*/
|
||||
[ qualident(&nd)
|
||||
[ ':' qualtype(&tp)
|
||||
/* This is correct, in both kinds of Modula-2, if
|
||||
the first qualident is a single identifier.
|
||||
*/
|
||||
{ if (nd->nd_class != Name) {
|
||||
error("illegal variant tag");
|
||||
}
|
||||
else {
|
||||
df = define(nd->nd_IDF, scope, D_FIELD);
|
||||
*palign = lcm(*palign, tp->tp_align);
|
||||
if (!(tp->tp_fund & T_DISCRETE)) {
|
||||
error("illegal type in variant");
|
||||
}
|
||||
df->df_type = tp;
|
||||
df->fld_off = align(*cnt, tp->tp_align);
|
||||
*cnt = df->fld_off + tp->tp_size;
|
||||
df->df_flags |= D_QEXPORTED;
|
||||
}
|
||||
FreeNode(nd);
|
||||
}
|
||||
| /* Old fashioned! the first qualident now represents
|
||||
the type
|
||||
*/
|
||||
{ warning(W_OLDFASHIONED,
|
||||
"old fashioned Modula-2 syntax; ':' missing");
|
||||
tp = qualified_type(nd);
|
||||
}
|
||||
]
|
||||
| ':' qualtype(&tp)
|
||||
/* Aha, third edition. Well done! */
|
||||
]
|
||||
{ tcnt = *cnt; }
|
||||
OF variant(scope, &tcnt, tp, palign)
|
||||
{ max = tcnt; tcnt = *cnt; }
|
||||
[
|
||||
'|' variant(scope, &tcnt, tp, palign)
|
||||
{ if (tcnt > max) max = tcnt; tcnt = *cnt; }
|
||||
]*
|
||||
[ ELSE FieldListSequence(scope, &tcnt, palign)
|
||||
{ if (tcnt > max) max = tcnt; }
|
||||
]?
|
||||
END
|
||||
{ *cnt = max; }
|
||||
]?
|
||||
;
|
||||
|
||||
variant(struct scope *scope; arith *cnt; struct type *tp; int *palign;)
|
||||
{
|
||||
struct node *nd;
|
||||
} :
|
||||
[
|
||||
CaseLabelList(&tp, &nd)
|
||||
{ /* Ignore the cases for the time being.
|
||||
Maybe a checking version will be supplied
|
||||
later ???
|
||||
*/
|
||||
FreeNode(nd);
|
||||
}
|
||||
':' FieldListSequence(scope, cnt, palign)
|
||||
]?
|
||||
/* Changed rule in new modula-2 */
|
||||
;
|
||||
|
||||
CaseLabelList(struct type **ptp; struct node **pnd;):
|
||||
CaseLabels(ptp, pnd)
|
||||
[
|
||||
{ *pnd = dot2node(Link, *pnd, NULLNODE); }
|
||||
',' CaseLabels(ptp, &((*pnd)->nd_right))
|
||||
{ pnd = &((*pnd)->nd_right); }
|
||||
]*
|
||||
;
|
||||
|
||||
CaseLabels(struct type **ptp; register struct node **pnd;)
|
||||
{
|
||||
register struct node *nd;
|
||||
}:
|
||||
ConstExpression(pnd)
|
||||
{
|
||||
if (*ptp != 0) {
|
||||
ChkCompat(pnd, *ptp, "case label");
|
||||
}
|
||||
nd = *pnd;
|
||||
}
|
||||
[
|
||||
UPTO { *pnd = dot2node(Link,nd,NULLNODE); }
|
||||
ConstExpression(&(*pnd)->nd_right)
|
||||
{ if (!ChkCompat(&((*pnd)->nd_right), nd->nd_type,
|
||||
"case label")) {
|
||||
nd->nd_type = error_type;
|
||||
}
|
||||
}
|
||||
]?
|
||||
{
|
||||
*ptp = nd->nd_type;
|
||||
}
|
||||
;
|
||||
|
||||
SetType(struct type **ptp;) :
|
||||
SET OF SimpleType(ptp)
|
||||
{ *ptp = set_type(*ptp); }
|
||||
;
|
||||
|
||||
/* In a pointer type definition, the type pointed at does not
|
||||
have to be declared yet, so be careful about identifying
|
||||
type-identifiers
|
||||
*/
|
||||
PointerType(register struct type **ptp;) :
|
||||
{ *ptp = construct_type(T_POINTER, NULLTYPE); }
|
||||
POINTER TO
|
||||
[ %if (type_or_forward(ptp))
|
||||
type(&((*ptp)->tp_next))
|
||||
|
|
||||
IDENT
|
||||
]
|
||||
;
|
||||
|
||||
qualtype(struct type **ptp;)
|
||||
{
|
||||
struct node *nd;
|
||||
} :
|
||||
qualident(&nd)
|
||||
{ *ptp = qualified_type(nd); }
|
||||
;
|
||||
|
||||
ProcedureType(struct type **ptp;) :
|
||||
PROCEDURE
|
||||
[
|
||||
FormalTypeList(ptp)
|
||||
|
|
||||
{ *ptp = proc_type((struct type *) 0,
|
||||
(struct paramlist *) 0,
|
||||
(arith) 0);
|
||||
}
|
||||
]
|
||||
;
|
||||
|
||||
FormalTypeList(struct type **ptp;)
|
||||
{
|
||||
struct paramlist *pr = 0;
|
||||
arith parmaddr = 0;
|
||||
} :
|
||||
'('
|
||||
[
|
||||
VarFormalType(&pr, &parmaddr)
|
||||
[
|
||||
',' VarFormalType(&pr, &parmaddr)
|
||||
]*
|
||||
]?
|
||||
')'
|
||||
[ ':' qualtype(ptp)
|
||||
| { *ptp = 0; }
|
||||
]
|
||||
{ *ptp = proc_type(*ptp, pr, parmaddr); }
|
||||
;
|
||||
|
||||
VarFormalType(struct paramlist **ppr; arith *parmaddr;)
|
||||
{
|
||||
struct type *tp;
|
||||
int isvar;
|
||||
} :
|
||||
var(&isvar)
|
||||
FormalType(&tp)
|
||||
{ EnterParamList(ppr,NULLNODE,tp,isvar,parmaddr); }
|
||||
;
|
||||
|
||||
var(int *VARp;) :
|
||||
[
|
||||
VAR { *VARp = D_VARPAR; }
|
||||
|
|
||||
/* empty */ { *VARp = D_VALPAR; }
|
||||
]
|
||||
;
|
||||
|
||||
ConstantDeclaration
|
||||
{
|
||||
struct idf *id;
|
||||
struct node *nd;
|
||||
register struct def *df;
|
||||
}:
|
||||
IDENT { id = dot.TOK_IDF; }
|
||||
'=' ConstExpression(&nd)
|
||||
{ df = define(id,CurrentScope,D_CONST);
|
||||
df->con_const = nd->nd_token;
|
||||
df->df_type = nd->nd_type;
|
||||
FreeNode(nd);
|
||||
}
|
||||
;
|
||||
|
||||
VariableDeclaration
|
||||
{
|
||||
struct node *VarList;
|
||||
register struct node *nd;
|
||||
struct type *tp;
|
||||
} :
|
||||
IdentAddr(&VarList)
|
||||
{ nd = VarList; }
|
||||
[ %persistent
|
||||
',' IdentAddr(&(nd->nd_right))
|
||||
{ nd = nd->nd_right; }
|
||||
]*
|
||||
':' type(&tp)
|
||||
{ EnterVarList(VarList, tp, proclevel > 0); }
|
||||
;
|
||||
|
||||
IdentAddr(struct node **pnd;)
|
||||
{
|
||||
register struct node *nd;
|
||||
} :
|
||||
IDENT { nd = dot2leaf(Name); }
|
||||
[ '['
|
||||
ConstExpression(&(nd->nd_left))
|
||||
']'
|
||||
]?
|
||||
{ *pnd = nd; }
|
||||
;
|
||||
142
lang/m2/comp/def.H
Normal file
142
lang/m2/comp/def.H
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* I D E N T I F I E R D E S C R I P T O R S T R U C T U R E */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
struct module {
|
||||
struct node *mo_priority;/* priority of a module */
|
||||
struct scopelist *mo_vis;/* scope of this module */
|
||||
struct node *mo_body; /* body of this module */
|
||||
#define mod_priority df_value.df_module.mo_priority
|
||||
#define mod_vis df_value.df_module.mo_vis
|
||||
#define mod_body df_value.df_module.mo_body
|
||||
};
|
||||
|
||||
struct variable {
|
||||
arith va_off; /* address or offset of variable */
|
||||
char *va_name; /* name of variable if given */
|
||||
#define var_off df_value.df_variable.va_off
|
||||
#define var_name df_value.df_variable.va_name
|
||||
};
|
||||
|
||||
struct constant {
|
||||
struct token co_const; /* result of a constant expression */
|
||||
#define con_const df_value.df_constant.co_const
|
||||
};
|
||||
|
||||
struct enumval {
|
||||
arith en_val; /* value of this enumeration literal */
|
||||
struct def *en_next; /* next enumeration literal */
|
||||
#define enm_val df_value.df_enum.en_val
|
||||
#define enm_next df_value.df_enum.en_next
|
||||
};
|
||||
|
||||
struct field {
|
||||
arith fd_off;
|
||||
struct variant {
|
||||
struct caselabellist *v_cases;
|
||||
label v_casedescr;
|
||||
struct def *v_varianttag;
|
||||
} *fd_variant;
|
||||
#define fld_off df_value.df_field.fd_off
|
||||
#define fld_variant df_value.df_field.fd_variant
|
||||
};
|
||||
|
||||
struct dfproc {
|
||||
struct scopelist *pr_vis; /* scope of procedure */
|
||||
struct node *pr_body; /* body of this procedure */
|
||||
#define prc_vis df_value.df_proc.pr_vis
|
||||
#define prc_body df_value.df_proc.pr_body
|
||||
};
|
||||
|
||||
struct import {
|
||||
struct def *im_def; /* imported definition */
|
||||
#define imp_def df_value.df_import.im_def
|
||||
};
|
||||
|
||||
struct dforward {
|
||||
struct scopelist *fo_vis;
|
||||
struct node *fo_node;
|
||||
char *fo_name;
|
||||
#define for_node df_value.df_forward.fo_node
|
||||
#define for_vis df_value.df_forward.fo_vis
|
||||
#define for_name df_value.df_forward.fo_name
|
||||
};
|
||||
|
||||
struct forwtype {
|
||||
struct node *f_node;
|
||||
#define df_forw_node df_value.df_fortype.f_node
|
||||
};
|
||||
|
||||
struct def { /* list of definitions for a name */
|
||||
struct def *df_next; /* next definition in definitions chain */
|
||||
struct def *df_nextinscope;
|
||||
/* link all definitions in a scope */
|
||||
struct idf *df_idf; /* link back to the name */
|
||||
struct scope *df_scope; /* scope in which this definition resides */
|
||||
unsigned short df_kind; /* the kind of this definition: */
|
||||
#define D_MODULE 0x0001 /* a module */
|
||||
#define D_PROCEDURE 0x0002 /* procedure of function */
|
||||
#define D_VARIABLE 0x0004 /* a variable */
|
||||
#define D_FIELD 0x0008 /* a field in a record */
|
||||
#define D_TYPE 0x0010 /* a type */
|
||||
#define D_ENUM 0x0020 /* an enumeration literal */
|
||||
#define D_CONST 0x0040 /* a constant */
|
||||
#define D_IMPORT 0x0080 /* an imported definition */
|
||||
#define D_PROCHEAD 0x0100 /* a procedure heading in a definition module */
|
||||
#define D_HIDDEN 0x0200 /* a hidden type */
|
||||
#define D_FORWARD 0x0400 /* not yet defined */
|
||||
#define D_FORWMODULE 0x0800 /* module must be declared later */
|
||||
#define D_FORWTYPE 0x1000 /* forward type */
|
||||
#define D_FTYPE 0x2000 /* resolved forward type */
|
||||
#define D_ERROR 0x4000 /* a compiler generated definition for an
|
||||
undefined variable
|
||||
*/
|
||||
#define D_VALUE (D_PROCEDURE|D_VARIABLE|D_FIELD|D_ENUM|D_CONST|D_PROCHEAD)
|
||||
#define D_ISTYPE (D_HIDDEN|D_TYPE|D_FTYPE)
|
||||
#define is_type(dfx) ((dfx)->df_kind & D_ISTYPE)
|
||||
unsigned short df_flags;
|
||||
#define D_NOREG 0x01 /* set if it may not reside in a register */
|
||||
#define D_USED 0x02 /* set if used (future use ???) */
|
||||
#define D_DEFINED 0x04 /* set if it is assigned a value (future use ???) */
|
||||
#define D_VARPAR 0x08 /* set if it is a VAR parameter */
|
||||
#define D_VALPAR 0x10 /* set if it is a value parameter */
|
||||
#define D_EXPORTED 0x20 /* set if exported */
|
||||
#define D_QEXPORTED 0x40 /* set if qualified exported */
|
||||
#define D_BUSY 0x80 /* set if busy reading this definition module */
|
||||
#define D_FOREIGN 0x100 /* set for foreign language modules */
|
||||
#define D_ADDRGIVEN 0x200 /* set if address given for variable */
|
||||
#define D_FORLOOP 0x400 /* set if busy in for-loop */
|
||||
struct type *df_type;
|
||||
union {
|
||||
struct module df_module;
|
||||
struct variable df_variable;
|
||||
struct constant df_constant;
|
||||
struct enumval df_enum;
|
||||
struct field df_field;
|
||||
struct import df_import;
|
||||
struct dfproc df_proc;
|
||||
struct dforward df_forward;
|
||||
struct forwtype df_fortype;
|
||||
int df_stdname; /* define for standard name */
|
||||
} df_value;
|
||||
};
|
||||
|
||||
/* ALLOCDEF "def" 50 */
|
||||
|
||||
extern struct def
|
||||
*define(),
|
||||
*DefineLocalModule(),
|
||||
*MkDef(),
|
||||
*DeclProc();
|
||||
|
||||
extern struct def
|
||||
*lookup(),
|
||||
*lookfor();
|
||||
#define NULLDEF ((struct def *) 0)
|
||||
381
lang/m2/comp/def.c
Normal file
381
lang/m2/comp/def.c
Normal file
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* D E F I N I T I O N M E C H A N I S M */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <alloc.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "LLlex.h"
|
||||
#include "main.h"
|
||||
#include "def.h"
|
||||
#include "type.h"
|
||||
#include "idf.h"
|
||||
#include "scope.h"
|
||||
#include "node.h"
|
||||
#include "Lpars.h"
|
||||
|
||||
STATIC
|
||||
DefInFront(df)
|
||||
register struct def *df;
|
||||
{
|
||||
/* Put definition "df" in front of the list of definitions
|
||||
in its scope.
|
||||
This is neccessary because in some cases the order in this
|
||||
list is important.
|
||||
*/
|
||||
register struct def *df1 = df->df_scope->sc_def;
|
||||
|
||||
if (df1 != df) {
|
||||
/* Definition "df" is not in front of the list
|
||||
*/
|
||||
while (df1) {
|
||||
/* Find definition "df"
|
||||
*/
|
||||
if (df1->df_nextinscope == df) {
|
||||
/* It already was in the list. Remove it
|
||||
*/
|
||||
df1->df_nextinscope = df->df_nextinscope;
|
||||
break;
|
||||
}
|
||||
df1 = df1->df_nextinscope;
|
||||
}
|
||||
|
||||
/* Now put it in front
|
||||
*/
|
||||
df->df_nextinscope = df->df_scope->sc_def;
|
||||
df->df_scope->sc_def = df;
|
||||
}
|
||||
}
|
||||
|
||||
struct def *
|
||||
MkDef(id, scope, kind)
|
||||
register struct idf *id;
|
||||
register struct scope *scope;
|
||||
{
|
||||
/* Create a new definition structure in scope "scope", with
|
||||
id "id" and kind "kind".
|
||||
*/
|
||||
register struct def *df;
|
||||
|
||||
df = new_def();
|
||||
df->df_idf = id;
|
||||
df->df_scope = scope;
|
||||
df->df_kind = kind;
|
||||
df->df_next = id->id_def;
|
||||
id->id_def = df;
|
||||
|
||||
/* enter the definition in the list of definitions in this scope
|
||||
*/
|
||||
df->df_nextinscope = scope->sc_def;
|
||||
scope->sc_def = df;
|
||||
return df;
|
||||
}
|
||||
|
||||
struct def *
|
||||
define(id, scope, kind)
|
||||
register struct idf *id;
|
||||
register struct scope *scope;
|
||||
int kind;
|
||||
{
|
||||
/* Declare an identifier in a scope, but first check if it
|
||||
already has been defined.
|
||||
If so, then check for the cases in which this is legal,
|
||||
and otherwise give an error message.
|
||||
*/
|
||||
register struct def *df;
|
||||
|
||||
df = lookup(id, scope, 1);
|
||||
if ( /* Already in this scope */
|
||||
df
|
||||
|| /* A closed scope, and id defined in the pervasive scope */
|
||||
(
|
||||
scopeclosed(scope)
|
||||
&&
|
||||
(df = lookup(id, PervasiveScope, 1)))
|
||||
) {
|
||||
switch(df->df_kind) {
|
||||
case D_HIDDEN:
|
||||
/* An opaque type. We may now have found the
|
||||
definition of this type.
|
||||
*/
|
||||
if (kind == D_TYPE && !DefinitionModule) {
|
||||
df->df_kind = D_TYPE;
|
||||
return df;
|
||||
}
|
||||
break;
|
||||
|
||||
case D_FORWMODULE:
|
||||
/* A forward reference to a module. We may have found
|
||||
another one, or we may have found the definition
|
||||
for this module.
|
||||
*/
|
||||
if (kind == D_FORWMODULE) {
|
||||
return df;
|
||||
}
|
||||
|
||||
if (kind == D_MODULE) {
|
||||
FreeNode(df->for_node);
|
||||
df->mod_vis = df->for_vis;
|
||||
df->df_kind = kind;
|
||||
DefInFront(df);
|
||||
return df;
|
||||
}
|
||||
break;
|
||||
|
||||
case D_TYPE:
|
||||
if (kind == D_FORWTYPE) return df;
|
||||
break;
|
||||
case D_FORWTYPE:
|
||||
if (kind == D_FORWTYPE) return df;
|
||||
if (kind == D_TYPE) {
|
||||
df->df_kind = D_FTYPE;
|
||||
}
|
||||
else {
|
||||
error("identifier \"%s\" must be a type",
|
||||
id->id_text);
|
||||
}
|
||||
return df;
|
||||
|
||||
case D_FORWARD:
|
||||
/* A forward reference, for which we may now have
|
||||
found a definition.
|
||||
*/
|
||||
if (kind != D_FORWARD) {
|
||||
FreeNode(df->for_node);
|
||||
}
|
||||
|
||||
/* Fall through */
|
||||
|
||||
case D_ERROR:
|
||||
/* A definition generated by the compiler, because
|
||||
it found an error. Maybe, the user gives a
|
||||
definition after all.
|
||||
*/
|
||||
df->df_kind = kind;
|
||||
return df;
|
||||
}
|
||||
|
||||
if (kind != D_ERROR) {
|
||||
/* Avoid spurious error messages
|
||||
*/
|
||||
error("identifier \"%s\" already declared",
|
||||
id->id_text);
|
||||
}
|
||||
|
||||
return df;
|
||||
}
|
||||
|
||||
return MkDef(id, scope, kind);
|
||||
}
|
||||
|
||||
RemoveImports(pdf)
|
||||
register struct def **pdf;
|
||||
{
|
||||
/* Remove all imports from a definition module. This is
|
||||
neccesary because the implementation module might import
|
||||
them again.
|
||||
*/
|
||||
register struct def *df = *pdf;
|
||||
|
||||
while (df) {
|
||||
if (df->df_kind == D_IMPORT) {
|
||||
RemoveFromIdList(df);
|
||||
*pdf = df->df_nextinscope;
|
||||
free_def(df);
|
||||
}
|
||||
else {
|
||||
pdf = &(df->df_nextinscope);
|
||||
}
|
||||
df = *pdf;
|
||||
}
|
||||
}
|
||||
|
||||
RemoveFromIdList(df)
|
||||
register struct def *df;
|
||||
{
|
||||
/* Remove definition "df" from the definition list
|
||||
*/
|
||||
register struct idf *id = df->df_idf;
|
||||
register struct def *df1;
|
||||
|
||||
if ((df1 = id->id_def) == df) id->id_def = df->df_next;
|
||||
else {
|
||||
while (df1->df_next != df) {
|
||||
assert(df1->df_next != 0);
|
||||
df1 = df1->df_next;
|
||||
}
|
||||
df1->df_next = df->df_next;
|
||||
}
|
||||
}
|
||||
|
||||
struct def *
|
||||
DeclProc(type, id)
|
||||
register struct idf *id;
|
||||
{
|
||||
/* A procedure is declared, either in a definition or a program
|
||||
module. Create a def structure for it (if neccessary).
|
||||
Also create a name for it.
|
||||
*/
|
||||
register struct def *df;
|
||||
register struct scope *scope;
|
||||
extern char *sprint();
|
||||
static int nmcount;
|
||||
char buf[256];
|
||||
|
||||
assert(type & (D_PROCEDURE | D_PROCHEAD));
|
||||
|
||||
if (type == D_PROCHEAD) {
|
||||
/* In a definition module
|
||||
*/
|
||||
df = define(id, CurrentScope, type);
|
||||
df->for_node = dot2leaf(Name);
|
||||
if (CurrentScope->sc_definedby->df_flags & D_FOREIGN) {
|
||||
df->for_name = id->id_text;
|
||||
}
|
||||
else {
|
||||
sprint(buf,"%s_%s",CurrentScope->sc_name,id->id_text);
|
||||
df->for_name = Salloc(buf, (unsigned) (strlen(buf)+1));
|
||||
}
|
||||
if (CurrVis == Defined->mod_vis) {
|
||||
/* The current module will define this routine.
|
||||
make sure the name is exported.
|
||||
*/
|
||||
C_exp(df->for_name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
char *name;
|
||||
|
||||
df = lookup(id, CurrentScope, 1);
|
||||
if (df && df->df_kind == D_PROCHEAD) {
|
||||
/* C_exp already generated when we saw the definition
|
||||
in the definition module
|
||||
*/
|
||||
df->df_kind = D_PROCEDURE;
|
||||
name = df->for_name;
|
||||
DefInFront(df);
|
||||
}
|
||||
else {
|
||||
df = define(id, CurrentScope, type);
|
||||
sprint(buf,"_%d_%s",++nmcount,id->id_text);
|
||||
name = Salloc(buf, (unsigned)(strlen(buf)+1));
|
||||
if (options['x']) {
|
||||
C_exp(buf);
|
||||
}
|
||||
else C_inp(buf);
|
||||
}
|
||||
open_scope(OPENSCOPE);
|
||||
scope = CurrentScope;
|
||||
scope->sc_name = name;
|
||||
scope->sc_definedby = df;
|
||||
}
|
||||
df->prc_vis = CurrVis;
|
||||
|
||||
return df;
|
||||
}
|
||||
|
||||
EndProc(df, id)
|
||||
register struct def *df;
|
||||
struct idf *id;
|
||||
{
|
||||
/* The end of a procedure declaration.
|
||||
Check that the closing identifier matches the name of the
|
||||
procedure, close the scope, and check that a function
|
||||
procedure has at least one RETURN statement.
|
||||
*/
|
||||
extern int return_occurred;
|
||||
|
||||
match_id(id, df->df_idf);
|
||||
close_scope(SC_CHKFORW|SC_REVERSE);
|
||||
if (! return_occurred && ResultType(df->df_type)) {
|
||||
error("function procedure %s does not return a value",
|
||||
df->df_idf->id_text);
|
||||
}
|
||||
}
|
||||
|
||||
struct def *
|
||||
DefineLocalModule(id)
|
||||
struct idf *id;
|
||||
{
|
||||
/* Create a definition for a local module. Also give it
|
||||
a name to be used for code generation.
|
||||
*/
|
||||
register struct def *df = define(id, CurrentScope, D_MODULE);
|
||||
register struct scope *sc;
|
||||
static int modulecount = 0;
|
||||
char buf[256];
|
||||
extern char *sprint();
|
||||
extern int proclevel;
|
||||
|
||||
sprint(buf, "_%d%s", ++modulecount, id->id_text);
|
||||
|
||||
if (!df->mod_vis) {
|
||||
/* We never saw the name of this module before. Create a
|
||||
scope for it.
|
||||
*/
|
||||
open_scope(CLOSEDSCOPE);
|
||||
df->mod_vis = CurrVis;
|
||||
}
|
||||
|
||||
CurrVis = df->mod_vis;
|
||||
|
||||
sc = CurrentScope;
|
||||
sc->sc_level = proclevel;
|
||||
sc->sc_definedby = df;
|
||||
sc->sc_name = Salloc(buf, (unsigned) (strlen(buf) + 1));
|
||||
|
||||
/* Create a type for it
|
||||
*/
|
||||
df->df_type = standard_type(T_RECORD, 1, (arith) 0);
|
||||
df->df_type->rec_scope = sc;
|
||||
|
||||
/* Generate code that indicates that the initialization procedure
|
||||
for this module is local.
|
||||
*/
|
||||
if (options['x']) {
|
||||
C_exp(buf);
|
||||
}
|
||||
else C_inp(buf);
|
||||
|
||||
return df;
|
||||
}
|
||||
|
||||
CheckWithDef(df, tp)
|
||||
register struct def *df;
|
||||
struct type *tp;
|
||||
{
|
||||
/* Check the header of a procedure declaration against a
|
||||
possible earlier definition in the definition module.
|
||||
*/
|
||||
|
||||
if (df->df_type) {
|
||||
/* We already saw a definition of this type
|
||||
in the definition module.
|
||||
*/
|
||||
if (!TstProcEquiv(tp, df->df_type)) {
|
||||
error("inconsistent procedure declaration for \"%s\"",
|
||||
df->df_idf->id_text);
|
||||
}
|
||||
FreeType(df->df_type);
|
||||
}
|
||||
df->df_type = tp;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
PrDef(df)
|
||||
register struct def *df;
|
||||
{
|
||||
print("n: %s, k: %d\n", df->df_idf->id_text, df->df_kind);
|
||||
}
|
||||
#endif DEBUG
|
||||
22
lang/m2/comp/def_sizes.h
Normal file
22
lang/m2/comp/def_sizes.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/* D E F A U L T S I Z E S A N D A L I G N M E N T S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#define MAXSIZE 8 /* the maximum of the SZ_* constants */
|
||||
/* target machine sizes */
|
||||
#define SZ_CHAR (arith)1
|
||||
#define SZ_WORD (arith)4
|
||||
#define SZ_INT (arith)4
|
||||
#define SZ_LONG (arith)4
|
||||
#define SZ_FLOAT (arith)4
|
||||
#define SZ_DOUBLE (arith)8
|
||||
#define SZ_POINTER (arith)4
|
||||
/* target machine alignment requirements */
|
||||
#define AL_CHAR 1
|
||||
#define AL_WORD (int) SZ_WORD
|
||||
#define AL_INT (int) SZ_WORD
|
||||
#define AL_LONG (int) SZ_WORD
|
||||
#define AL_FLOAT (int) SZ_WORD
|
||||
#define AL_DOUBLE (int) SZ_WORD
|
||||
#define AL_POINTER (int) SZ_WORD
|
||||
#define AL_STRUCT 1
|
||||
166
lang/m2/comp/defmodule.c
Normal file
166
lang/m2/comp/defmodule.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* D E F I N I T I O N M O D U L E S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <alloc.h>
|
||||
|
||||
#include "idf.h"
|
||||
#include "input.h"
|
||||
#include "scope.h"
|
||||
#include "LLlex.h"
|
||||
#include "def.h"
|
||||
#include "Lpars.h"
|
||||
#include "f_info.h"
|
||||
#include "main.h"
|
||||
#include "node.h"
|
||||
#include "type.h"
|
||||
#include "misc.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
long sys_filesize();
|
||||
#endif
|
||||
|
||||
struct idf *DefId;
|
||||
|
||||
char *
|
||||
getwdir(fn)
|
||||
register char *fn;
|
||||
{
|
||||
register char *p;
|
||||
char *strrindex();
|
||||
|
||||
p = strrindex(fn, '/');
|
||||
while (p && *(p + 1) == '\0') { /* remove trailing /'s */
|
||||
*p = '\0';
|
||||
p = strrindex(fn, '/');
|
||||
}
|
||||
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
fn = Salloc(fn, (unsigned) (p - &fn[0] + 1));
|
||||
*p = '/';
|
||||
return fn;
|
||||
}
|
||||
else return ".";
|
||||
}
|
||||
|
||||
STATIC
|
||||
GetFile(name)
|
||||
char *name;
|
||||
{
|
||||
/* Try to find a file with basename "name" and extension ".def",
|
||||
in the directories mentioned in "DEFPATH".
|
||||
*/
|
||||
char buf[15];
|
||||
char *strncpy(), *strcat();
|
||||
|
||||
strncpy(buf, name, 10);
|
||||
buf[10] = '\0'; /* maximum length */
|
||||
strcat(buf, ".def");
|
||||
DEFPATH[0] = WorkingDir;
|
||||
if (! InsertFile(buf, DEFPATH, &(FileName))) {
|
||||
error("could not find a DEFINITION MODULE for \"%s\"", name);
|
||||
return 0;
|
||||
}
|
||||
WorkingDir = getwdir(FileName);
|
||||
LineNumber = 1;
|
||||
DO_DEBUG(options['F'], debug("File %s : %ld characters", FileName, sys_filesize(FileName)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct def *
|
||||
GetDefinitionModule(id, incr)
|
||||
register struct idf *id;
|
||||
{
|
||||
/* Return a pointer to the "def" structure of the definition
|
||||
module indicated by "id".
|
||||
We may have to read the definition module itself.
|
||||
Also increment level by "incr".
|
||||
*/
|
||||
register struct def *df;
|
||||
static int level;
|
||||
struct scopelist *vis;
|
||||
char *fn = FileName;
|
||||
int ln = LineNumber;
|
||||
struct scope *newsc = CurrentScope;
|
||||
|
||||
level += incr;
|
||||
df = lookup(id, GlobalScope, 1);
|
||||
if (!df) {
|
||||
/* Read definition module. Make an exception for SYSTEM.
|
||||
*/
|
||||
DefId = id;
|
||||
if (!strcmp(id->id_text, "SYSTEM")) {
|
||||
do_SYSTEM();
|
||||
df = lookup(id, GlobalScope, 1);
|
||||
}
|
||||
else {
|
||||
extern int ForeignFlag;
|
||||
|
||||
ForeignFlag = 0;
|
||||
open_scope(CLOSEDSCOPE);
|
||||
newsc = CurrentScope;
|
||||
if (!is_anon_idf(id) && GetFile(id->id_text)) {
|
||||
|
||||
DefModule();
|
||||
df = lookup(id, GlobalScope, 1);
|
||||
if (level == 1 &&
|
||||
(!df || !(df->df_flags & D_FOREIGN))) {
|
||||
/* The module is directly imported by
|
||||
the currently defined module, and
|
||||
is not foreign, so we have to
|
||||
remember its name because we have
|
||||
to call its initialization routine
|
||||
*/
|
||||
static struct node *nd_end;
|
||||
register struct node *n;
|
||||
extern struct node *Modules;
|
||||
|
||||
n = dot2leaf(Name);
|
||||
n->nd_IDF = id;
|
||||
n->nd_symb = IDENT;
|
||||
if (nd_end) nd_end->nd_left = n;
|
||||
else Modules = n;
|
||||
nd_end = n;
|
||||
}
|
||||
}
|
||||
else {
|
||||
df = lookup(id, GlobalScope, 1);
|
||||
newsc->sc_name = id->id_text;
|
||||
}
|
||||
vis = CurrVis;
|
||||
close_scope(SC_CHKFORW);
|
||||
}
|
||||
if (! df) {
|
||||
df = MkDef(id, GlobalScope, D_ERROR);
|
||||
df->df_type = error_type;
|
||||
df->mod_vis = vis;
|
||||
newsc->sc_definedby = df;
|
||||
}
|
||||
}
|
||||
else if (df->df_flags & D_BUSY) {
|
||||
error("definition module \"%s\" depends on itself",
|
||||
id->id_text);
|
||||
}
|
||||
else if (df == Defined && level == 1) {
|
||||
error("cannot import from current module \"%s\"", id->id_text);
|
||||
df->df_kind = D_ERROR;
|
||||
}
|
||||
FileName = fn;
|
||||
LineNumber = ln;
|
||||
assert(df);
|
||||
level -= incr;
|
||||
return df;
|
||||
}
|
||||
65
lang/m2/comp/desig.H
Normal file
65
lang/m2/comp/desig.H
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* D E S I G N A T O R D E S C R I P T I O N S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* Generating code for designators is not particularly easy, especially if
|
||||
you don't know wether you want the address or the value.
|
||||
The next structure is used to generate code for designators.
|
||||
It contains information on how to find the designator, after generation
|
||||
of the code that is common to both address and value computations.
|
||||
*/
|
||||
|
||||
struct desig {
|
||||
int dsg_kind;
|
||||
#define DSG_INIT 0 /* don't know anything yet */
|
||||
#define DSG_LOADED 1 /* designator loaded on top of the stack */
|
||||
#define DSG_PLOADED 2 /* designator accessible through pointer on
|
||||
stack, possibly with an offset
|
||||
*/
|
||||
#define DSG_FIXED 3 /* designator directly accessible */
|
||||
#define DSG_PFIXED 4 /* designator accessible through directly
|
||||
accessible pointer
|
||||
*/
|
||||
#define DSG_INDEXED 5 /* designator accessible through array
|
||||
operation. Address of array descriptor on
|
||||
top of the stack, index beneath that, and
|
||||
base address beneath that
|
||||
*/
|
||||
arith dsg_offset; /* contains an offset for PLOADED,
|
||||
or for FIXED or PFIXED it contains an
|
||||
offset from dsg_name, if it exists,
|
||||
or from the current Local Base
|
||||
*/
|
||||
char *dsg_name; /* name of global variable, used for
|
||||
FIXED and PFIXED
|
||||
*/
|
||||
struct def *dsg_def; /* def structure associated with this
|
||||
designator, or 0
|
||||
*/
|
||||
};
|
||||
|
||||
/* The next structure describes the designator in a with-statement.
|
||||
We have a linked list of them, as with-statements may be nested.
|
||||
*/
|
||||
|
||||
struct withdesig {
|
||||
struct withdesig *w_next;
|
||||
struct scope *w_scope; /* scope in which fields of this record
|
||||
reside
|
||||
*/
|
||||
struct desig w_desig; /* a desig structure for this particular
|
||||
designator
|
||||
*/
|
||||
};
|
||||
|
||||
extern struct withdesig *WithDesigs;
|
||||
extern struct desig InitDesig;
|
||||
|
||||
#define NO_LABEL ((label) 0)
|
||||
616
lang/m2/comp/desig.c
Normal file
616
lang/m2/comp/desig.c
Normal file
@@ -0,0 +1,616 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* D E S I G N A T O R E V A L U A T I O N */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* Code generation for designators.
|
||||
This file contains some routines that generate code common to address
|
||||
as well as value computations, and leave a description in a "desig"
|
||||
structure. It also contains routines to load an address, load a value
|
||||
or perform a store.
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <em_code.h>
|
||||
#include <assert.h>
|
||||
#include <alloc.h>
|
||||
|
||||
#include "type.h"
|
||||
#include "LLlex.h"
|
||||
#include "def.h"
|
||||
#include "scope.h"
|
||||
#include "desig.h"
|
||||
#include "node.h"
|
||||
#include "warning.h"
|
||||
|
||||
extern int proclevel;
|
||||
|
||||
int
|
||||
WordOrDouble(ds, size)
|
||||
register struct desig *ds;
|
||||
arith size;
|
||||
{
|
||||
return ((int) (ds->dsg_offset) % (int) word_size == 0 &&
|
||||
( (int) size == (int) word_size ||
|
||||
(int) size == (int) dword_size));
|
||||
}
|
||||
|
||||
int
|
||||
DoLoad(ds, size)
|
||||
register struct desig *ds;
|
||||
arith size;
|
||||
{
|
||||
if (! WordOrDouble(ds, size)) return 0;
|
||||
if (ds->dsg_name) {
|
||||
if ((int) size == (int) word_size) {
|
||||
C_loe_dnam(ds->dsg_name, ds->dsg_offset);
|
||||
}
|
||||
else C_lde_dnam(ds->dsg_name, ds->dsg_offset);
|
||||
}
|
||||
else {
|
||||
if ((int) size == (int) word_size) {
|
||||
C_lol(ds->dsg_offset);
|
||||
}
|
||||
else C_ldl(ds->dsg_offset);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
DoStore(ds, size)
|
||||
register struct desig *ds;
|
||||
arith size;
|
||||
{
|
||||
if (! WordOrDouble(ds, size)) return 0;
|
||||
if (ds->dsg_name) {
|
||||
if ((int) size == (int) word_size) {
|
||||
C_ste_dnam(ds->dsg_name, ds->dsg_offset);
|
||||
}
|
||||
else C_sde_dnam(ds->dsg_name, ds->dsg_offset);
|
||||
}
|
||||
else {
|
||||
if ((int) size == (int) word_size) {
|
||||
C_stl(ds->dsg_offset);
|
||||
}
|
||||
else C_sdl(ds->dsg_offset);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
properly(ds, tp)
|
||||
register struct desig *ds;
|
||||
register struct type *tp;
|
||||
{
|
||||
/* Check if it is allowed to load or store the value indicated
|
||||
by "ds" with LOI/STI.
|
||||
- if the size is not either a multiple or a dividor of the
|
||||
wordsize, then not.
|
||||
- if the alignment is at least "word" then OK.
|
||||
- if size is dividor of word_size and alignment >= size then OK.
|
||||
- otherwise check alignment of address. This can only be done
|
||||
with DSG_FIXED.
|
||||
*/
|
||||
|
||||
int szmodword = (int) (tp->tp_size) % (int) word_size;
|
||||
/* 0 if multiple of wordsize */
|
||||
int wordmodsz = word_size % tp->tp_size;/* 0 if dividor of wordsize */
|
||||
|
||||
if (szmodword && wordmodsz) return 0;
|
||||
if (tp->tp_align >= word_align) return 1;
|
||||
if (szmodword && tp->tp_align >= szmodword) return 1;
|
||||
|
||||
return ds->dsg_kind == DSG_FIXED &&
|
||||
((! szmodword && (int) (ds->dsg_offset) % word_align == 0) ||
|
||||
(! wordmodsz && ds->dsg_offset % tp->tp_size == 0));
|
||||
}
|
||||
|
||||
CodeValue(ds, tp)
|
||||
register struct desig *ds;
|
||||
register struct type *tp;
|
||||
{
|
||||
/* Generate code to load the value of the designator described
|
||||
in "ds"
|
||||
*/
|
||||
arith sz;
|
||||
|
||||
switch(ds->dsg_kind) {
|
||||
case DSG_LOADED:
|
||||
break;
|
||||
|
||||
case DSG_FIXED:
|
||||
if (DoLoad(ds, tp->tp_size)) break;
|
||||
/* Fall through */
|
||||
case DSG_PLOADED:
|
||||
case DSG_PFIXED:
|
||||
sz = WA(tp->tp_size);
|
||||
if (properly(ds, tp)) {
|
||||
CodeAddress(ds);
|
||||
C_loi(tp->tp_size);
|
||||
break;
|
||||
}
|
||||
if (ds->dsg_kind == DSG_PLOADED) {
|
||||
sz -= pointer_size;
|
||||
|
||||
C_asp(-sz);
|
||||
C_lor((arith) 1);
|
||||
C_adp(sz);
|
||||
C_loi(pointer_size);
|
||||
}
|
||||
else {
|
||||
C_asp(-sz);
|
||||
}
|
||||
CodeAddress(ds);
|
||||
C_loc(tp->tp_size);
|
||||
C_cal("_load");
|
||||
C_asp(2 * word_size);
|
||||
break;
|
||||
|
||||
case DSG_INDEXED:
|
||||
C_lar(word_size);
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeValue)");
|
||||
}
|
||||
|
||||
ds->dsg_kind = DSG_LOADED;
|
||||
}
|
||||
|
||||
ChkForFOR(nd)
|
||||
struct node *nd;
|
||||
{
|
||||
if (nd->nd_class == Def) {
|
||||
register struct def *df = nd->nd_def;
|
||||
|
||||
if (df->df_flags & D_FORLOOP) {
|
||||
node_warning(nd,
|
||||
W_ORDINARY,
|
||||
"assignment to FOR-loop control variable");
|
||||
df->df_flags &= ~D_FORLOOP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CodeStore(ds, tp)
|
||||
register struct desig *ds;
|
||||
register struct type *tp;
|
||||
{
|
||||
/* Generate code to store the value on the stack in the designator
|
||||
described in "ds"
|
||||
*/
|
||||
struct desig save;
|
||||
|
||||
save = *ds;
|
||||
|
||||
switch(ds->dsg_kind) {
|
||||
case DSG_FIXED:
|
||||
if (DoStore(ds, tp->tp_size)) break;
|
||||
/* Fall through */
|
||||
case DSG_PLOADED:
|
||||
case DSG_PFIXED:
|
||||
CodeAddress(&save);
|
||||
if (properly(ds, tp)) {
|
||||
C_sti(tp->tp_size);
|
||||
break;
|
||||
}
|
||||
C_loc(tp->tp_size);
|
||||
C_cal("_store");
|
||||
C_asp(2 * word_size + WA(tp->tp_size));
|
||||
break;
|
||||
|
||||
case DSG_INDEXED:
|
||||
C_sar(word_size);
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeStore)");
|
||||
}
|
||||
|
||||
ds->dsg_kind = DSG_INIT;
|
||||
}
|
||||
|
||||
CodeCopy(lhs, rhs, sz, psize)
|
||||
register struct desig *lhs, *rhs;
|
||||
arith sz, *psize;
|
||||
{
|
||||
struct desig l, r;
|
||||
|
||||
l = *lhs; r = *rhs;
|
||||
*psize -= sz;
|
||||
lhs->dsg_offset += sz;
|
||||
rhs->dsg_offset += sz;
|
||||
CodeAddress(&r);
|
||||
C_loi(sz);
|
||||
CodeAddress(&l);
|
||||
C_sti(sz);
|
||||
}
|
||||
|
||||
CodeMove(rhs, left, rtp)
|
||||
register struct desig *rhs;
|
||||
register struct node *left;
|
||||
struct type *rtp;
|
||||
{
|
||||
register struct desig *lhs = new_desig();
|
||||
register struct type *tp = left->nd_type;
|
||||
int loadedflag = 0;
|
||||
|
||||
/* Generate code for an assignment. Testing of type
|
||||
compatibility and the like is already done.
|
||||
Go through some (considerable) trouble to see if a BLM can be
|
||||
generated.
|
||||
*/
|
||||
|
||||
ChkForFOR(left);
|
||||
switch(rhs->dsg_kind) {
|
||||
case DSG_LOADED:
|
||||
CodeDesig(left, lhs);
|
||||
if (rtp->tp_fund == T_STRING) {
|
||||
CodeAddress(lhs);
|
||||
C_loc(rtp->tp_size);
|
||||
C_loc(tp->tp_size);
|
||||
C_cal("_StringAssign");
|
||||
C_asp(word_size << 2);
|
||||
break;
|
||||
}
|
||||
CodeStore(lhs, tp);
|
||||
break;
|
||||
case DSG_PLOADED:
|
||||
case DSG_PFIXED:
|
||||
CodeAddress(rhs);
|
||||
if ((int) (tp->tp_size) % (int) word_size == 0 &&
|
||||
tp->tp_align >= (int) word_size) {
|
||||
CodeDesig(left, lhs);
|
||||
CodeAddress(lhs);
|
||||
C_blm(tp->tp_size);
|
||||
break;
|
||||
}
|
||||
CodeValue(rhs, tp);
|
||||
CodeDStore(left);
|
||||
break;
|
||||
case DSG_FIXED:
|
||||
CodeDesig(left, lhs);
|
||||
if (lhs->dsg_kind == DSG_FIXED &&
|
||||
(int) (lhs->dsg_offset) % (int) word_size ==
|
||||
(int) (rhs->dsg_offset) % (int) word_size) {
|
||||
register int sz;
|
||||
arith size = tp->tp_size;
|
||||
|
||||
while (size &&
|
||||
(sz = ((int)(lhs->dsg_offset) % (int)word_size))) {
|
||||
/* First copy up to word-aligned
|
||||
boundaries
|
||||
*/
|
||||
if (sz < 0) sz = -sz; /* bloody '%' */
|
||||
while ((int) word_size % sz) sz--;
|
||||
CodeCopy(lhs, rhs, (arith) sz, &size);
|
||||
}
|
||||
if (size > 3*dword_size) {
|
||||
/* Do a block move
|
||||
*/
|
||||
struct desig l, r;
|
||||
arith sz;
|
||||
|
||||
sz = (size / word_size) * word_size;
|
||||
l = *lhs; r = *rhs;
|
||||
CodeAddress(&r);
|
||||
CodeAddress(&l);
|
||||
C_blm((arith) sz);
|
||||
rhs->dsg_offset += sz;
|
||||
lhs->dsg_offset += sz;
|
||||
size -= sz;
|
||||
}
|
||||
else for (sz = (int) dword_size; sz; sz -= (int) word_size) {
|
||||
while (size >= sz) {
|
||||
/* Then copy dwords, words.
|
||||
Depend on peephole optimizer
|
||||
*/
|
||||
CodeCopy(lhs, rhs, (arith) sz, &size);
|
||||
}
|
||||
}
|
||||
sz = word_size;
|
||||
while (size && --sz) {
|
||||
/* And then copy remaining parts
|
||||
*/
|
||||
while ((int) word_size % sz) sz--;
|
||||
while (size >= sz) {
|
||||
CodeCopy(lhs, rhs, (arith) sz, &size);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (lhs->dsg_kind == DSG_PLOADED ||
|
||||
lhs->dsg_kind == DSG_INDEXED) {
|
||||
CodeAddress(lhs);
|
||||
loadedflag = 1;
|
||||
}
|
||||
if ((int)(tp->tp_size) % (int) word_size == 0 &&
|
||||
tp->tp_align >= word_size) {
|
||||
CodeAddress(rhs);
|
||||
if (loadedflag) C_exg(pointer_size);
|
||||
else CodeAddress(lhs);
|
||||
C_blm(tp->tp_size);
|
||||
break;
|
||||
}
|
||||
{
|
||||
arith tmp;
|
||||
extern arith NewPtr();
|
||||
|
||||
if (loadedflag) {
|
||||
tmp = NewPtr();
|
||||
lhs->dsg_offset = tmp;
|
||||
lhs->dsg_name = 0;
|
||||
lhs->dsg_kind = DSG_PFIXED;
|
||||
lhs->dsg_def = 0;
|
||||
C_stl(tmp); /* address of lhs */
|
||||
}
|
||||
CodeValue(rhs, tp);
|
||||
CodeStore(lhs, tp);
|
||||
if (loadedflag) FreePtr(tmp);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
crash("CodeMove");
|
||||
}
|
||||
free_desig(lhs);
|
||||
}
|
||||
|
||||
CodeAddress(ds)
|
||||
register struct desig *ds;
|
||||
{
|
||||
/* Generate code to load the address of the designator described
|
||||
in "ds"
|
||||
*/
|
||||
|
||||
switch(ds->dsg_kind) {
|
||||
case DSG_PLOADED:
|
||||
if (ds->dsg_offset) {
|
||||
C_adp(ds->dsg_offset);
|
||||
}
|
||||
break;
|
||||
|
||||
case DSG_FIXED:
|
||||
if (ds->dsg_name) {
|
||||
C_lae_dnam(ds->dsg_name, ds->dsg_offset);
|
||||
break;
|
||||
}
|
||||
C_lal(ds->dsg_offset);
|
||||
if (ds->dsg_def) ds->dsg_def->df_flags |= D_NOREG;
|
||||
break;
|
||||
|
||||
case DSG_PFIXED:
|
||||
DoLoad(ds, word_size);
|
||||
break;
|
||||
|
||||
case DSG_INDEXED:
|
||||
C_aar(word_size);
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeAddress)");
|
||||
}
|
||||
|
||||
ds->dsg_offset = 0;
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
}
|
||||
|
||||
CodeFieldDesig(df, ds)
|
||||
register struct def *df;
|
||||
register struct desig *ds;
|
||||
{
|
||||
/* Generate code for a field designator. Only the code common for
|
||||
address as well as value computation is generated, and the
|
||||
resulting information on where to find the designator is placed
|
||||
in "ds". "df" indicates the definition of the field.
|
||||
*/
|
||||
|
||||
if (ds->dsg_kind == DSG_INIT) {
|
||||
/* In a WITH statement. We must find the designator in the
|
||||
WITH statement, and act as if the field is a selection
|
||||
of this designator.
|
||||
So, first find the right WITH statement, which is the
|
||||
first one of the proper record type, which is
|
||||
recognized by its scope indication.
|
||||
*/
|
||||
register struct withdesig *wds = WithDesigs;
|
||||
|
||||
assert(wds != 0);
|
||||
|
||||
while (wds->w_scope != df->df_scope) {
|
||||
wds = wds->w_next;
|
||||
assert(wds != 0);
|
||||
}
|
||||
|
||||
/* Found it. Now, act like it was a selection.
|
||||
*/
|
||||
*ds = wds->w_desig;
|
||||
assert(ds->dsg_kind == DSG_PFIXED);
|
||||
}
|
||||
|
||||
switch(ds->dsg_kind) {
|
||||
case DSG_PLOADED:
|
||||
case DSG_FIXED:
|
||||
ds->dsg_offset += df->fld_off;
|
||||
break;
|
||||
|
||||
case DSG_PFIXED:
|
||||
case DSG_INDEXED:
|
||||
CodeAddress(ds);
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
ds->dsg_offset = df->fld_off;
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeFieldDesig)");
|
||||
}
|
||||
}
|
||||
|
||||
CodeVarDesig(df, ds)
|
||||
register struct def *df;
|
||||
register struct desig *ds;
|
||||
{
|
||||
/* Generate code for a variable represented by a "def" structure.
|
||||
Of course, there are numerous cases: the variable is local,
|
||||
it is a value parameter, it is a var parameter, it is one of
|
||||
those of an enclosing procedure, or it is global.
|
||||
*/
|
||||
register struct scope *sc = df->df_scope;
|
||||
|
||||
/* Selections from a module are handled earlier, when identifying
|
||||
the variable, so ...
|
||||
*/
|
||||
assert(ds->dsg_kind == DSG_INIT);
|
||||
|
||||
if (df->df_flags & D_ADDRGIVEN) {
|
||||
/* the programmer specified an address in the declaration of
|
||||
the variable. Generate code to push the address.
|
||||
*/
|
||||
CodeConst(df->var_off, (int) pointer_size);
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
ds->dsg_offset = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (df->var_name) {
|
||||
/* this variable has been given a name, so it is global.
|
||||
It is directly accessible.
|
||||
*/
|
||||
ds->dsg_name = df->var_name;
|
||||
ds->dsg_offset = 0;
|
||||
ds->dsg_kind = DSG_FIXED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc->sc_level != proclevel) {
|
||||
/* the variable is local to a statically enclosing procedure.
|
||||
*/
|
||||
assert(proclevel > sc->sc_level);
|
||||
|
||||
df->df_flags |= D_NOREG;
|
||||
if (df->df_flags & (D_VARPAR|D_VALPAR)) {
|
||||
/* value or var parameter
|
||||
*/
|
||||
C_lxa((arith) (proclevel - sc->sc_level));
|
||||
if ((df->df_flags & D_VARPAR) ||
|
||||
IsConformantArray(df->df_type)) {
|
||||
/* var parameter or conformant array.
|
||||
For conformant array's, the address is
|
||||
passed.
|
||||
*/
|
||||
C_adp(df->var_off);
|
||||
C_loi(pointer_size);
|
||||
ds->dsg_offset = 0;
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else C_lxl((arith) (proclevel - sc->sc_level));
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
ds->dsg_offset = df->var_off;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now, finally, we have a local variable or a local parameter
|
||||
*/
|
||||
if ((df->df_flags & D_VARPAR) || IsConformantArray(df->df_type)) {
|
||||
/* a var parameter; address directly accessible.
|
||||
*/
|
||||
ds->dsg_kind = DSG_PFIXED;
|
||||
}
|
||||
else ds->dsg_kind = DSG_FIXED;
|
||||
ds->dsg_offset = df->var_off;
|
||||
ds->dsg_def = df;
|
||||
}
|
||||
|
||||
CodeDesig(nd, ds)
|
||||
register struct node *nd;
|
||||
register struct desig *ds;
|
||||
{
|
||||
/* Generate code for a designator. Use divide and conquer
|
||||
principle
|
||||
*/
|
||||
register struct def *df;
|
||||
|
||||
switch(nd->nd_class) { /* Divide */
|
||||
case Def:
|
||||
df = nd->nd_def;
|
||||
if (nd->nd_left) CodeDesig(nd->nd_left, ds);
|
||||
|
||||
switch(df->df_kind) {
|
||||
case D_FIELD:
|
||||
CodeFieldDesig(df, ds);
|
||||
break;
|
||||
|
||||
case D_VARIABLE:
|
||||
CodeVarDesig(df, ds);
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeDesig) Def");
|
||||
}
|
||||
break;
|
||||
|
||||
case Arrsel:
|
||||
assert(nd->nd_symb == '[');
|
||||
|
||||
CodeDesig(nd->nd_left, ds);
|
||||
CodeAddress(ds);
|
||||
CodePExpr(nd->nd_right);
|
||||
|
||||
/* Now load address of descriptor
|
||||
*/
|
||||
if (IsConformantArray(nd->nd_left->nd_type)) {
|
||||
assert(nd->nd_left->nd_class == Def);
|
||||
|
||||
df = nd->nd_left->nd_def;
|
||||
if (proclevel > df->df_scope->sc_level) {
|
||||
C_lxa((arith) (proclevel - df->df_scope->sc_level));
|
||||
C_adp(df->var_off + pointer_size);
|
||||
}
|
||||
else C_lal(df->var_off + pointer_size);
|
||||
}
|
||||
else {
|
||||
C_lae_dlb(nd->nd_left->nd_type->arr_descr, (arith) 0);
|
||||
}
|
||||
ds->dsg_kind = DSG_INDEXED;
|
||||
break;
|
||||
|
||||
case Arrow:
|
||||
assert(nd->nd_symb == '^');
|
||||
|
||||
CodeDesig(nd->nd_right, ds);
|
||||
switch(ds->dsg_kind) {
|
||||
case DSG_LOADED:
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
break;
|
||||
|
||||
case DSG_INDEXED:
|
||||
case DSG_PLOADED:
|
||||
case DSG_PFIXED:
|
||||
CodeValue(ds, nd->nd_right->nd_type);
|
||||
ds->dsg_kind = DSG_PLOADED;
|
||||
ds->dsg_offset = 0;
|
||||
break;
|
||||
|
||||
case DSG_FIXED:
|
||||
ds->dsg_kind = DSG_PFIXED;
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeDesig) Uoper");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(CodeDesig) class");
|
||||
}
|
||||
}
|
||||
84
lang/m2/comp/em_m2.6
Normal file
84
lang/m2/comp/em_m2.6
Normal file
@@ -0,0 +1,84 @@
|
||||
.TH EM_M2 6ACK
|
||||
.ad
|
||||
.SH NAME
|
||||
em_m2 \- ACK Modula\-2 compiler
|
||||
.SH SYNOPSIS
|
||||
.B em_m2
|
||||
.RI [ option ]
|
||||
.I source
|
||||
.I destination
|
||||
.SH DESCRIPTION
|
||||
.I Em_m2
|
||||
is a
|
||||
compiler, part of the Amsterdam Compiler Kit, that translates Modula-2 programs
|
||||
into EM code.
|
||||
The input is taken from
|
||||
.IR source ,
|
||||
while the
|
||||
EM code is written on
|
||||
.IR destination .
|
||||
.br
|
||||
.I Option
|
||||
is a, possibly empty, sequence of the following combinations:
|
||||
.IP \fB\-I\fIdirname\fR
|
||||
.br
|
||||
append \fIdirname\fR to the list of directories where definition modules
|
||||
are looked for.
|
||||
.PP
|
||||
When the compiler needs a definition module, it is first searched for
|
||||
in the current directory, and then in the directories given to it by the
|
||||
\-\fBI\fR flag
|
||||
in the order given.
|
||||
.IP \fB\-M\fP\fIn\fP
|
||||
set maximum identifier length to \fIn\fP.
|
||||
The minimum value for \fIn\fR is 14, because the keyword
|
||||
"IMPLEMENTATION" is that long.
|
||||
.IP \fB\-n\fR
|
||||
do not generate EM register messages.
|
||||
The user-declared variables will not be stored into registers on the target
|
||||
machine.
|
||||
.IP \fB\-L\fR
|
||||
do not generate the EM \fBfil\fR and \fBlin\fR instructions that enable
|
||||
an interpreter to keep track of the current location in the source code.
|
||||
.IP \fB\-V\fIcm\fR.\fIn\fR,\ \fB\-V\fIcm\fR.\fIncm\fR.\fIn\fR\ ...
|
||||
.br
|
||||
set the size and alignment requirements.
|
||||
The letter \fIc\fR indicates the simple type, which is one of
|
||||
\fBw\fR(word size), \fBi\fR(INTEGER), \fBl\fR(LONGINT), \fBf\fR(REAL),
|
||||
\fBd\fR(LONGREAL), or \fBp\fR(POINTER).
|
||||
It may also be the letter \fBS\fR, indicating that an initial
|
||||
record alignment follows.
|
||||
The \fIm\fR parameter can be used to specify the length of the type (in bytes)
|
||||
and the \fIn\fR parameter for the alignment of that type.
|
||||
Absence of \fIm\fR or \fIn\fR causes a default value to be retained.
|
||||
.IP \fB\-w\fR\fIclasses\fR
|
||||
suppress warning messages whose class is a member of \fIclasses\fR.
|
||||
Currently, there are three classes: \fBO\fR, indicating old-flashioned use,
|
||||
\fBW\fR, indicating "ordinary" warnings, and \fBR\fR, indicating
|
||||
restricted Modula-2.
|
||||
If no \fIclasses\fR are given, all warnings are suppressed.
|
||||
By default, warnings in class \fBO\fR and \fBW\fR are given.
|
||||
.IP \fB\-W\fR\fIclasses\fR
|
||||
allow for warning messages whose class is a member of \fIclasses\fR.
|
||||
.IP \fB\-x\fR
|
||||
make all procedure names global, so that \fIadb\fR(1) understands them.
|
||||
.IP \fB\-i\fR\fInum\fR
|
||||
maximum number of bits in a set. When not used, a default value is
|
||||
retained.
|
||||
.IP \fB\-s\fR
|
||||
make INTEGER ranges symmetric, t.i., MIN(INTEGER) = - MAX(INTEGER).
|
||||
This is useful for interpreters that use the "real" MIN(INTEGER) to
|
||||
indicate "undefined".
|
||||
.IP \fB-R\fR
|
||||
disable all range checks.
|
||||
.LP
|
||||
.SH FILES
|
||||
.IR ~em/lib/em_m2 :
|
||||
binary of the Modula-2 compiler.
|
||||
.SH SEE ALSO
|
||||
\fIack\fR(1), \fImodula-2\fR(1)
|
||||
.SH DIAGNOSTICS
|
||||
All warning and error messages are written on standard error output.
|
||||
.SH REMARKS
|
||||
Debugging and profiling facilities may be present during the development
|
||||
of \fIem_m2\fP.
|
||||
479
lang/m2/comp/enter.c
Normal file
479
lang/m2/comp/enter.c
Normal file
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* H I G H L E V E L S Y M B O L E N T R Y */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <alloc.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <em_code.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "idf.h"
|
||||
#include "LLlex.h"
|
||||
#include "def.h"
|
||||
#include "type.h"
|
||||
#include "scope.h"
|
||||
#include "node.h"
|
||||
#include "main.h"
|
||||
#include "misc.h"
|
||||
#include "f_info.h"
|
||||
|
||||
struct def *
|
||||
Enter(name, kind, type, pnam)
|
||||
char *name;
|
||||
struct type *type;
|
||||
{
|
||||
/* Enter a definition for "name" with kind "kind" and type
|
||||
"type" in the Current Scope. If it is a standard name, also
|
||||
put its number in the definition structure.
|
||||
*/
|
||||
register struct def *df;
|
||||
|
||||
df = define(str2idf(name, 0), CurrentScope, kind);
|
||||
df->df_type = type;
|
||||
if (pnam) df->df_value.df_stdname = pnam;
|
||||
return df;
|
||||
}
|
||||
|
||||
EnterType(name, type)
|
||||
char *name;
|
||||
struct type *type;
|
||||
{
|
||||
/* Enter a type definition for "name" and type
|
||||
"type" in the Current Scope.
|
||||
*/
|
||||
|
||||
Enter(name, D_TYPE, type, 0);
|
||||
}
|
||||
|
||||
EnterEnumList(Idlist, type)
|
||||
struct node *Idlist;
|
||||
register struct type *type;
|
||||
{
|
||||
/* Put a list of enumeration literals in the symbol table.
|
||||
They all have type "type".
|
||||
Also assign numbers to them, and link them together.
|
||||
We must link them together because an enumeration type may
|
||||
be exported, in which case its literals must also be exported.
|
||||
Thus, we need an easy way to get to them.
|
||||
*/
|
||||
register struct def *df;
|
||||
register struct node *idlist = Idlist;
|
||||
|
||||
type->enm_ncst = 0;
|
||||
for (; idlist; idlist = idlist->nd_left) {
|
||||
df = define(idlist->nd_IDF, CurrentScope, D_ENUM);
|
||||
df->df_type = type;
|
||||
df->enm_val = (type->enm_ncst)++;
|
||||
df->enm_next = type->enm_enums;
|
||||
type->enm_enums = df;
|
||||
}
|
||||
FreeNode(Idlist);
|
||||
}
|
||||
|
||||
EnterFieldList(Idlist, type, scope, addr)
|
||||
struct node *Idlist;
|
||||
register struct type *type;
|
||||
struct scope *scope;
|
||||
arith *addr;
|
||||
{
|
||||
/* Put a list of fields in the symbol table.
|
||||
They all have type "type", and are put in scope "scope".
|
||||
Mark them as QUALIFIED EXPORT, because that's exactly what
|
||||
fields are, you can get to them by qualifying them.
|
||||
*/
|
||||
register struct def *df;
|
||||
register struct node *idlist = Idlist;
|
||||
|
||||
for (; idlist; idlist = idlist->nd_left) {
|
||||
df = define(idlist->nd_IDF, scope, D_FIELD);
|
||||
df->df_type = type;
|
||||
df->df_flags |= D_QEXPORTED;
|
||||
df->fld_off = align(*addr, type->tp_align);
|
||||
*addr = df->fld_off + type->tp_size;
|
||||
}
|
||||
FreeNode(Idlist);
|
||||
}
|
||||
|
||||
EnterVarList(Idlist, type, local)
|
||||
struct node *Idlist;
|
||||
struct type *type;
|
||||
{
|
||||
/* Enter a list of identifiers representing variables into the
|
||||
name list. "type" represents the type of the variables.
|
||||
"local" is set if the variables are declared local to a
|
||||
procedure.
|
||||
*/
|
||||
register struct def *df;
|
||||
register struct node *idlist = Idlist;
|
||||
register struct scopelist *sc = CurrVis;
|
||||
char buf[256];
|
||||
extern char *sprint();
|
||||
|
||||
if (local) {
|
||||
/* Find the closest enclosing open scope. This
|
||||
is the procedure that we are dealing with
|
||||
*/
|
||||
while (sc->sc_scope->sc_scopeclosed) sc = enclosing(sc);
|
||||
}
|
||||
|
||||
for (; idlist; idlist = idlist->nd_right) {
|
||||
df = define(idlist->nd_IDF, CurrentScope, D_VARIABLE);
|
||||
df->df_type = type;
|
||||
if (idlist->nd_left) {
|
||||
/* An address was supplied
|
||||
*/
|
||||
register struct type *tp = idlist->nd_left->nd_type;
|
||||
|
||||
df->df_flags |= D_ADDRGIVEN | D_NOREG;
|
||||
if (tp != error_type && !(tp->tp_fund & T_CARDINAL)){
|
||||
node_error(idlist->nd_left,
|
||||
"illegal type for address");
|
||||
}
|
||||
df->var_off = idlist->nd_left->nd_INT;
|
||||
}
|
||||
else if (local) {
|
||||
/* subtract aligned size of variable to the offset,
|
||||
as the variable list exists only local to a
|
||||
procedure
|
||||
*/
|
||||
sc->sc_scope->sc_off =
|
||||
-WA(align(type->tp_size - sc->sc_scope->sc_off,
|
||||
type->tp_align));
|
||||
df->var_off = sc->sc_scope->sc_off;
|
||||
}
|
||||
else {
|
||||
/* Global name, possibly external
|
||||
*/
|
||||
if (sc->sc_scope->sc_definedby->df_flags & D_FOREIGN) {
|
||||
df->var_name = df->df_idf->id_text;
|
||||
}
|
||||
else {
|
||||
sprint(buf,"%s_%s", sc->sc_scope->sc_name,
|
||||
df->df_idf->id_text);
|
||||
df->var_name = Salloc(buf,
|
||||
(unsigned)(strlen(buf)+1));
|
||||
}
|
||||
df->df_flags |= D_NOREG;
|
||||
|
||||
if (DefinitionModule) {
|
||||
if (sc == Defined->mod_vis) {
|
||||
C_exa_dnam(df->var_name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
C_ina_dnam(df->var_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
FreeNode(Idlist);
|
||||
}
|
||||
|
||||
EnterParamList(ppr, Idlist, type, VARp, off)
|
||||
struct paramlist **ppr;
|
||||
struct node *Idlist;
|
||||
struct type *type;
|
||||
int VARp;
|
||||
arith *off;
|
||||
{
|
||||
/* Create (part of) a parameterlist of a procedure.
|
||||
"ids" indicates the list of identifiers, "tp" their type, and
|
||||
"VARp" indicates D_VARPAR or D_VALPAR.
|
||||
*/
|
||||
register struct paramlist *pr;
|
||||
register struct def *df;
|
||||
register struct node *idlist = Idlist;
|
||||
struct node *dummy = 0;
|
||||
static struct paramlist *last;
|
||||
|
||||
if (! idlist) {
|
||||
/* Can only happen when a procedure type is defined */
|
||||
dummy = Idlist = idlist = dot2leaf(Name);
|
||||
}
|
||||
for ( ; idlist; idlist = idlist->nd_left) {
|
||||
pr = new_paramlist();
|
||||
pr->par_next = 0;
|
||||
if (!*ppr) *ppr = pr;
|
||||
else last->par_next = pr;
|
||||
last = pr;
|
||||
if (!DefinitionModule && idlist != dummy) {
|
||||
df = define(idlist->nd_IDF, CurrentScope, D_VARIABLE);
|
||||
df->var_off = *off;
|
||||
}
|
||||
else df = new_def();
|
||||
pr->par_def = df;
|
||||
df->df_type = type;
|
||||
df->df_flags = VARp;
|
||||
|
||||
if (IsConformantArray(type)) {
|
||||
/* we need room for the base address and a descriptor
|
||||
*/
|
||||
*off += pointer_size + 3 * word_size;
|
||||
}
|
||||
else if (VARp == D_VARPAR) {
|
||||
*off += pointer_size;
|
||||
}
|
||||
else {
|
||||
*off += WA(type->tp_size);
|
||||
}
|
||||
}
|
||||
FreeNode(Idlist);
|
||||
}
|
||||
|
||||
STATIC
|
||||
DoImport(df, scope)
|
||||
register struct def *df;
|
||||
struct scope *scope;
|
||||
{
|
||||
/* Definition "df" is imported to scope "scope".
|
||||
Handle the case that it is an enumeration type or a module.
|
||||
*/
|
||||
|
||||
define(df->df_idf, scope, D_IMPORT)->imp_def = df;
|
||||
|
||||
if (df->df_kind == D_TYPE && df->df_type->tp_fund == T_ENUMERATION) {
|
||||
/* Also import all enumeration literals
|
||||
*/
|
||||
for (df = df->df_type->enm_enums; df; df = df->enm_next) {
|
||||
define(df->df_idf, scope, D_IMPORT)->imp_def = df;
|
||||
}
|
||||
}
|
||||
else if (df->df_kind == D_MODULE) {
|
||||
/* Also import all definitions that are exported from this
|
||||
module
|
||||
*/
|
||||
if (df->mod_vis == CurrVis) {
|
||||
error("cannot import current module \"%s\"",
|
||||
df->df_idf->id_text);
|
||||
return;
|
||||
}
|
||||
for (df = df->mod_vis->sc_scope->sc_def;
|
||||
df;
|
||||
df = df->df_nextinscope) {
|
||||
if (df->df_flags & D_EXPORTED) {
|
||||
define(df->df_idf,scope,D_IMPORT)->imp_def = df;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC struct scopelist *
|
||||
ForwModule(df, nd)
|
||||
register struct def *df;
|
||||
struct node *nd;
|
||||
{
|
||||
/* An import is done from a not yet defined module "df".
|
||||
We could also end up here for not found DEFINITION MODULES.
|
||||
Create a declaration and a scope for this module.
|
||||
*/
|
||||
struct scopelist *vis;
|
||||
|
||||
if (df->df_scope != GlobalScope) {
|
||||
df->df_scope = enclosing(CurrVis)->sc_scope;
|
||||
df->df_kind = D_FORWMODULE;
|
||||
}
|
||||
open_scope(CLOSEDSCOPE);
|
||||
vis = CurrVis; /* The new scope, but watch out, it's "sc_encl"
|
||||
field is not set right. It must indicate the
|
||||
enclosing scope, but this must be done AFTER
|
||||
closing this one
|
||||
*/
|
||||
close_scope(0);
|
||||
vis->sc_encl = enclosing(CurrVis);
|
||||
/* Here ! */
|
||||
df->for_vis = vis;
|
||||
df->for_node = nd;
|
||||
return vis;
|
||||
}
|
||||
|
||||
STATIC struct def *
|
||||
ForwDef(ids, scope)
|
||||
register struct node *ids;
|
||||
struct scope *scope;
|
||||
{
|
||||
/* Enter a forward definition of "ids" in scope "scope",
|
||||
if it is not already defined.
|
||||
*/
|
||||
register struct def *df;
|
||||
|
||||
if (!(df = lookup(ids->nd_IDF, scope, 1))) {
|
||||
df = define(ids->nd_IDF, scope, D_FORWARD);
|
||||
df->for_node = MkLeaf(Name, &(ids->nd_token));
|
||||
}
|
||||
return df;
|
||||
}
|
||||
|
||||
EnterExportList(Idlist, qualified)
|
||||
struct node *Idlist;
|
||||
{
|
||||
/* From the current scope, the list of identifiers "ids" is
|
||||
exported. Note this fact. If the export is not qualified, make
|
||||
all the "ids" visible in the enclosing scope by defining them
|
||||
in this scope as "imported".
|
||||
*/
|
||||
register struct node *idlist = Idlist;
|
||||
register struct def *df, *df1;
|
||||
|
||||
for (;idlist; idlist = idlist->nd_left) {
|
||||
df = lookup(idlist->nd_IDF, CurrentScope, 0);
|
||||
|
||||
if (!df) {
|
||||
/* undefined item in export list
|
||||
*/
|
||||
node_error(idlist,
|
||||
"identifier \"%s\" not defined",
|
||||
idlist->nd_IDF->id_text);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (df->df_flags & (D_EXPORTED|D_QEXPORTED)) {
|
||||
node_error(idlist,
|
||||
"multiple occurrences of \"%s\" in export list",
|
||||
idlist->nd_IDF->id_text);
|
||||
}
|
||||
|
||||
if (df->df_kind == D_IMPORT) df = df->imp_def;
|
||||
|
||||
df->df_flags |= qualified;
|
||||
if (qualified == D_EXPORTED) {
|
||||
/* Export, but not qualified.
|
||||
Find all imports of the module in which this export
|
||||
occurs, and export the current definition to it
|
||||
*/
|
||||
df1 = CurrentScope->sc_definedby->df_idf->id_def;
|
||||
while (df1) {
|
||||
if (df1->df_kind == D_IMPORT &&
|
||||
df1->imp_def == CurrentScope->sc_definedby) {
|
||||
DoImport(df, df1->df_scope);
|
||||
}
|
||||
df1 = df1->df_next;
|
||||
}
|
||||
|
||||
/* Also handle the definition as if the enclosing
|
||||
scope imports it.
|
||||
*/
|
||||
df1 = lookup(idlist->nd_IDF,
|
||||
enclosing(CurrVis)->sc_scope, 1);
|
||||
if (df1) {
|
||||
/* It was already defined in the enclosing
|
||||
scope. There are two legal possibilities,
|
||||
which are examined below.
|
||||
*/
|
||||
if (df1->df_kind == D_PROCHEAD &&
|
||||
df->df_kind == D_PROCEDURE) {
|
||||
df1->df_kind = D_IMPORT;
|
||||
df1->imp_def = df;
|
||||
continue;
|
||||
}
|
||||
if (df1->df_kind == D_HIDDEN &&
|
||||
df->df_kind == D_TYPE) {
|
||||
DeclareType(idlist, df1, df->df_type);
|
||||
df1->df_kind = D_TYPE;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
DoImport(df, enclosing(CurrVis)->sc_scope);
|
||||
}
|
||||
}
|
||||
FreeNode(Idlist);
|
||||
}
|
||||
|
||||
EnterFromImportList(Idlist, FromDef, FromId)
|
||||
struct node *Idlist;
|
||||
register struct def *FromDef;
|
||||
struct node *FromId;
|
||||
{
|
||||
/* Import the list Idlist from the module indicated by Fromdef.
|
||||
*/
|
||||
register struct node *idlist = Idlist;
|
||||
register struct scopelist *vis;
|
||||
register struct def *df;
|
||||
char *module_name = FromDef->df_idf->id_text;
|
||||
int forwflag = 0;
|
||||
|
||||
switch(FromDef->df_kind) {
|
||||
case D_ERROR:
|
||||
/* The module from which the import was done
|
||||
is not yet declared. I'm not sure if I must
|
||||
accept this, but for the time being I will.
|
||||
We also end up here if some definition module could not
|
||||
be found.
|
||||
???
|
||||
*/
|
||||
vis = ForwModule(FromDef, FromId);
|
||||
forwflag = 1;
|
||||
break;
|
||||
case D_FORWMODULE:
|
||||
vis = FromDef->for_vis;
|
||||
break;
|
||||
case D_MODULE:
|
||||
vis = FromDef->mod_vis;
|
||||
if (vis == CurrVis) {
|
||||
node_error(FromId, "cannot import from current module \"%s\"", module_name);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
node_error(FromId,"identifier \"%s\" does not represent a module",module_name);
|
||||
return;
|
||||
}
|
||||
|
||||
for (; idlist; idlist = idlist->nd_left) {
|
||||
if (forwflag) df = ForwDef(idlist, vis->sc_scope);
|
||||
else if (! (df = lookup(idlist->nd_IDF, vis->sc_scope, 1))) {
|
||||
if (! is_anon_idf(idlist->nd_IDF)) {
|
||||
node_error(idlist,
|
||||
"identifier \"%s\" not declared in module \"%s\"",
|
||||
idlist->nd_IDF->id_text,
|
||||
module_name);
|
||||
}
|
||||
df = define(idlist->nd_IDF,vis->sc_scope,D_ERROR);
|
||||
}
|
||||
else if (! (df->df_flags & (D_EXPORTED|D_QEXPORTED))) {
|
||||
node_error(idlist,
|
||||
"identifier \"%s\" not exported from module \"%s\"",
|
||||
idlist->nd_IDF->id_text,
|
||||
module_name);
|
||||
df->df_flags |= D_QEXPORTED;
|
||||
}
|
||||
DoImport(df, CurrentScope);
|
||||
}
|
||||
|
||||
if (!forwflag) FreeNode(FromId);
|
||||
FreeNode(Idlist);
|
||||
}
|
||||
|
||||
EnterImportList(Idlist, local)
|
||||
struct node *Idlist;
|
||||
{
|
||||
/* Import "Idlist" from the enclosing scope.
|
||||
An exception must be made for imports of the compilation unit.
|
||||
In this case, definition modules must be read for "Idlist".
|
||||
This case is indicated by the value 0 of the "local" flag.
|
||||
*/
|
||||
register struct node *idlist = Idlist;
|
||||
struct scope *sc = enclosing(CurrVis)->sc_scope;
|
||||
extern struct def *GetDefinitionModule();
|
||||
struct f_info f;
|
||||
|
||||
f = file_info;
|
||||
|
||||
for (; idlist; idlist = idlist->nd_left) {
|
||||
DoImport(local ?
|
||||
ForwDef(idlist, sc) :
|
||||
GetDefinitionModule(idlist->nd_IDF, 1) ,
|
||||
CurrentScope);
|
||||
file_info = f;
|
||||
}
|
||||
FreeNode(Idlist);
|
||||
}
|
||||
242
lang/m2/comp/error.c
Normal file
242
lang/m2/comp/error.c
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* E R R O R A N D D I A G N O S T I C R O U T I N E S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* This file contains the (non-portable) error-message and diagnostic
|
||||
giving functions. Be aware that they are called with a variable
|
||||
number of arguments!
|
||||
*/
|
||||
|
||||
#include "errout.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <system.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "f_info.h"
|
||||
#include "LLlex.h"
|
||||
#include "main.h"
|
||||
#include "node.h"
|
||||
#include "warning.h"
|
||||
|
||||
/* error classes */
|
||||
#define ERROR 1
|
||||
#define WARNING 2
|
||||
#define LEXERROR 3
|
||||
#define LEXWARNING 4
|
||||
#define CRASH 5
|
||||
#define FATAL 6
|
||||
#ifdef DEBUG
|
||||
#define VDEBUG 7
|
||||
#endif
|
||||
|
||||
int err_occurred;
|
||||
static int warn_class;
|
||||
|
||||
extern char *symbol2str();
|
||||
|
||||
/* There are three general error-message functions:
|
||||
lexerror() lexical and pre-processor error messages
|
||||
error() syntactic and semantic error messages
|
||||
node_error() errors in nodes
|
||||
The difference lies in the place where the file name and line
|
||||
number come from.
|
||||
Lexical errors report from the global variables LineNumber and
|
||||
FileName, node errors get their information from the
|
||||
node, whereas other errors use the information in the token.
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
/*VARARGS1*/
|
||||
debug(fmt, args)
|
||||
char *fmt;
|
||||
{
|
||||
_error(VDEBUG, NULLNODE, fmt, &args);
|
||||
}
|
||||
#endif DEBUG
|
||||
|
||||
/*VARARGS1*/
|
||||
error(fmt, args)
|
||||
char *fmt;
|
||||
{
|
||||
_error(ERROR, NULLNODE, fmt, &args);
|
||||
}
|
||||
|
||||
/*VARARGS2*/
|
||||
node_error(node, fmt, args)
|
||||
struct node *node;
|
||||
char *fmt;
|
||||
{
|
||||
_error(ERROR, node, fmt, &args);
|
||||
}
|
||||
|
||||
/*VARARGS1*/
|
||||
warning(class, fmt, args)
|
||||
char *fmt;
|
||||
{
|
||||
warn_class = class;
|
||||
if (class & warning_classes) _error(WARNING, NULLNODE, fmt, &args);
|
||||
}
|
||||
|
||||
/*VARARGS2*/
|
||||
node_warning(node, class, fmt, args)
|
||||
struct node *node;
|
||||
char *fmt;
|
||||
{
|
||||
warn_class = class;
|
||||
if (class & warning_classes) _error(WARNING, node, fmt, &args);
|
||||
}
|
||||
|
||||
/*VARARGS1*/
|
||||
lexerror(fmt, args)
|
||||
char *fmt;
|
||||
{
|
||||
_error(LEXERROR, NULLNODE, fmt, &args);
|
||||
}
|
||||
|
||||
/*VARARGS1*/
|
||||
lexwarning(class, fmt, args)
|
||||
char *fmt;
|
||||
{
|
||||
warn_class = class;
|
||||
if (class & warning_classes) _error(LEXWARNING, NULLNODE, fmt, &args);
|
||||
}
|
||||
|
||||
/*VARARGS1*/
|
||||
fatal(fmt, args)
|
||||
char *fmt;
|
||||
int args;
|
||||
{
|
||||
|
||||
_error(FATAL, NULLNODE, fmt, &args);
|
||||
sys_stop(S_EXIT);
|
||||
}
|
||||
|
||||
/*VARARGS1*/
|
||||
crash(fmt, args)
|
||||
char *fmt;
|
||||
int args;
|
||||
{
|
||||
|
||||
_error(CRASH, NULLNODE, fmt, &args);
|
||||
#ifdef DEBUG
|
||||
sys_stop(S_ABORT);
|
||||
#else
|
||||
sys_stop(S_EXIT);
|
||||
#endif
|
||||
}
|
||||
|
||||
_error(class, node, fmt, argv)
|
||||
int class;
|
||||
struct node *node;
|
||||
char *fmt;
|
||||
int argv[];
|
||||
{
|
||||
/* _error attempts to limit the number of error messages
|
||||
for a given line to MAXERR_LINE.
|
||||
*/
|
||||
static unsigned int last_ln = 0;
|
||||
unsigned int ln = 0;
|
||||
static char * last_fn = 0;
|
||||
static int e_seen = 0;
|
||||
register char *remark = 0;
|
||||
|
||||
/* Since name and number are gathered from different places
|
||||
depending on the class, we first collect the relevant
|
||||
values and then decide what to print.
|
||||
*/
|
||||
/* preliminaries */
|
||||
switch (class) {
|
||||
case ERROR:
|
||||
case LEXERROR:
|
||||
case CRASH:
|
||||
case FATAL:
|
||||
if (C_busy()) C_ms_err();
|
||||
err_occurred = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* the remark */
|
||||
switch (class) {
|
||||
case WARNING:
|
||||
case LEXWARNING:
|
||||
switch(warn_class) {
|
||||
case W_OLDFASHIONED:
|
||||
remark = "(old-fashioned use)";
|
||||
break;
|
||||
case W_STRICT:
|
||||
remark = "(strict)";
|
||||
break;
|
||||
default:
|
||||
remark = "(warning)";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CRASH:
|
||||
remark = "CRASH\007";
|
||||
break;
|
||||
case FATAL:
|
||||
remark = "fatal error --";
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
case VDEBUG:
|
||||
remark = "(debug)";
|
||||
break;
|
||||
#endif DEBUG
|
||||
}
|
||||
|
||||
/* the place */
|
||||
switch (class) {
|
||||
case WARNING:
|
||||
case ERROR:
|
||||
ln = node ? node->nd_lineno : dot.tk_lineno;
|
||||
break;
|
||||
case LEXWARNING:
|
||||
case LEXERROR:
|
||||
case CRASH:
|
||||
case FATAL:
|
||||
#ifdef DEBUG
|
||||
case VDEBUG:
|
||||
#endif DEBUG
|
||||
ln = LineNumber;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (class != VDEBUG) {
|
||||
#endif
|
||||
if (FileName == last_fn && ln == last_ln) {
|
||||
/* we've seen this place before */
|
||||
e_seen++;
|
||||
if (e_seen == MAXERR_LINE) fmt = "etc ...";
|
||||
else
|
||||
if (e_seen > MAXERR_LINE)
|
||||
/* and too often, I'd say ! */
|
||||
return;
|
||||
}
|
||||
else {
|
||||
/* brand new place */
|
||||
last_ln = ln;
|
||||
last_fn = FileName;
|
||||
e_seen = 0;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
}
|
||||
#endif DEBUG
|
||||
|
||||
if (FileName) fprint(ERROUT, "\"%s\", line %u: ", FileName, ln);
|
||||
|
||||
if (remark) fprint(ERROUT, "%s ", remark);
|
||||
|
||||
doprnt(ERROUT, fmt, argv); /* contents of error */
|
||||
fprint(ERROUT, "\n");
|
||||
}
|
||||
290
lang/m2/comp/expression.g
Normal file
290
lang/m2/comp/expression.g
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* E X P R E S S I O N S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
{
|
||||
#include "debug.h"
|
||||
|
||||
#include <alloc.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "LLlex.h"
|
||||
#include "idf.h"
|
||||
#include "def.h"
|
||||
#include "node.h"
|
||||
#include "const.h"
|
||||
#include "type.h"
|
||||
#include "chk_expr.h"
|
||||
#include "warning.h"
|
||||
|
||||
extern char options[];
|
||||
}
|
||||
|
||||
/* inline, we need room for pdp/11
|
||||
number(struct node **p;) :
|
||||
[
|
||||
%default
|
||||
INTEGER
|
||||
|
|
||||
REAL
|
||||
] { *p = dot2leaf(Value);
|
||||
(*p)->nd_type = toktype;
|
||||
}
|
||||
;
|
||||
*/
|
||||
|
||||
qualident(struct node **p;)
|
||||
{
|
||||
} :
|
||||
IDENT { *p = dot2leaf(Name); }
|
||||
[
|
||||
selector(p)
|
||||
]*
|
||||
;
|
||||
|
||||
selector(struct node **pnd;):
|
||||
'.' { *pnd = dot2node(Link,*pnd,NULLNODE); }
|
||||
IDENT { (*pnd)->nd_IDF = dot.TOK_IDF; }
|
||||
;
|
||||
|
||||
ExpList(struct node **pnd;)
|
||||
{
|
||||
register struct node *nd;
|
||||
} :
|
||||
expression(pnd) { *pnd = nd = dot2node(Link,*pnd,NULLNODE);
|
||||
nd->nd_symb = ',';
|
||||
}
|
||||
[
|
||||
',' { nd->nd_right = dot2leaf(Link);
|
||||
nd = nd->nd_right;
|
||||
}
|
||||
expression(&(nd->nd_left))
|
||||
]*
|
||||
;
|
||||
|
||||
ConstExpression(struct node **pnd;)
|
||||
{
|
||||
register struct node *nd;
|
||||
}:
|
||||
expression(pnd)
|
||||
/*
|
||||
* Changed rule in new Modula-2.
|
||||
* Check that the expression is a constant expression and evaluate!
|
||||
*/
|
||||
{ nd = *pnd;
|
||||
DO_DEBUG(options['C'], print("CONSTANT EXPRESSION\n"));
|
||||
DO_DEBUG(options['C'], PrNode(nd, 0));
|
||||
|
||||
if (ChkExpression(nd) &&
|
||||
((nd)->nd_class != Set && (nd)->nd_class != Value)) {
|
||||
error("constant expression expected");
|
||||
}
|
||||
|
||||
DO_DEBUG(options['C'], print("RESULTS IN\n"));
|
||||
DO_DEBUG(options['C'], PrNode(nd, 0));
|
||||
}
|
||||
;
|
||||
|
||||
expression(struct node **pnd;)
|
||||
{
|
||||
} :
|
||||
SimpleExpression(pnd)
|
||||
[
|
||||
/* relation */
|
||||
[ '=' | '#' | '<' | LESSEQUAL | '>' | GREATEREQUAL | IN ]
|
||||
{ *pnd = dot2node(Oper, *pnd, NULLNODE); }
|
||||
SimpleExpression(&((*pnd)->nd_right))
|
||||
]?
|
||||
;
|
||||
|
||||
/* Inline in expression
|
||||
relation:
|
||||
'=' | '#' | '<' | LESSEQUAL | '>' | GREATEREQUAL | IN
|
||||
;
|
||||
*/
|
||||
|
||||
SimpleExpression(struct node **pnd;)
|
||||
{
|
||||
register struct node *nd = 0;
|
||||
} :
|
||||
[
|
||||
[ '+' | '-' ]
|
||||
{ nd = dot2leaf(Uoper);
|
||||
/* priority of unary operator ??? */
|
||||
}
|
||||
]?
|
||||
term(pnd)
|
||||
{ if (nd) {
|
||||
nd->nd_right = *pnd;
|
||||
*pnd = nd;
|
||||
}
|
||||
nd = *pnd;
|
||||
}
|
||||
[
|
||||
/* AddOperator */
|
||||
[ '+' | '-' | OR ]
|
||||
{ nd = dot2node(Oper, nd, NULLNODE); }
|
||||
term(&(nd->nd_right))
|
||||
]*
|
||||
{ *pnd = nd; }
|
||||
;
|
||||
|
||||
/* Inline in "SimpleExpression"
|
||||
AddOperator:
|
||||
'+' | '-' | OR
|
||||
;
|
||||
*/
|
||||
|
||||
term(struct node **pnd;)
|
||||
{
|
||||
register struct node *nd;
|
||||
}:
|
||||
factor(pnd) { nd = *pnd; }
|
||||
[
|
||||
/* MulOperator */
|
||||
[ '*' | '/' | DIV | MOD | AND ]
|
||||
{ nd = dot2node(Oper, nd, NULLNODE); }
|
||||
factor(&(nd->nd_right))
|
||||
]*
|
||||
{ *pnd = nd; }
|
||||
;
|
||||
|
||||
/* inline in "term"
|
||||
MulOperator:
|
||||
'*' | '/' | DIV | MOD | AND
|
||||
;
|
||||
*/
|
||||
|
||||
factor(register struct node **p;)
|
||||
{
|
||||
struct node *nd;
|
||||
} :
|
||||
qualident(p)
|
||||
[
|
||||
designator_tail(p)?
|
||||
[
|
||||
{ *p = dot2node(Call, *p, NULLNODE); }
|
||||
ActualParameters(&((*p)->nd_right))
|
||||
]?
|
||||
|
|
||||
bare_set(&nd)
|
||||
{ nd->nd_left = *p; *p = nd; }
|
||||
]
|
||||
|
|
||||
bare_set(p)
|
||||
| %default
|
||||
[
|
||||
%default
|
||||
INTEGER
|
||||
|
|
||||
REAL
|
||||
|
|
||||
STRING
|
||||
] { *p = dot2leaf(Value);
|
||||
(*p)->nd_type = toktype;
|
||||
}
|
||||
|
|
||||
'(' { nd = dot2leaf(Uoper); }
|
||||
expression(p)
|
||||
{ /* In some cases we must leave the '(' as an unary
|
||||
operator, because otherwise we cannot see that the
|
||||
factor was not a designator
|
||||
*/
|
||||
register int class = (*p)->nd_class;
|
||||
|
||||
if (class == Arrsel ||
|
||||
class == Arrow ||
|
||||
class == Name ||
|
||||
class == Link) {
|
||||
nd->nd_right = *p;
|
||||
*p = nd;
|
||||
}
|
||||
else free_node(nd);
|
||||
}
|
||||
')'
|
||||
|
|
||||
NOT { *p = dot2leaf(Uoper); }
|
||||
factor(&((*p)->nd_right))
|
||||
;
|
||||
|
||||
bare_set(struct node **pnd;)
|
||||
{
|
||||
register struct node *nd;
|
||||
} :
|
||||
'{' { dot.tk_symb = SET;
|
||||
*pnd = nd = dot2leaf(Xset);
|
||||
nd->nd_type = bitset_type;
|
||||
}
|
||||
[
|
||||
element(nd)
|
||||
[ { nd = nd->nd_right; }
|
||||
',' element(nd)
|
||||
]*
|
||||
]?
|
||||
'}'
|
||||
;
|
||||
|
||||
ActualParameters(struct node **pnd;):
|
||||
'(' ExpList(pnd)? ')'
|
||||
;
|
||||
|
||||
element(register struct node *nd;)
|
||||
{
|
||||
struct node *nd1;
|
||||
} :
|
||||
expression(&nd1)
|
||||
[
|
||||
UPTO
|
||||
{ nd1 = dot2node(Link, nd1, NULLNODE);}
|
||||
expression(&(nd1->nd_right))
|
||||
]?
|
||||
{ nd->nd_right = dot2node(Link, nd1, NULLNODE);
|
||||
nd->nd_right->nd_symb = ',';
|
||||
}
|
||||
;
|
||||
|
||||
designator(struct node **pnd;)
|
||||
:
|
||||
qualident(pnd)
|
||||
designator_tail(pnd)?
|
||||
;
|
||||
|
||||
designator_tail(struct node **pnd;):
|
||||
visible_designator_tail(pnd)
|
||||
[ %persistent
|
||||
%default
|
||||
selector(pnd)
|
||||
|
|
||||
visible_designator_tail(pnd)
|
||||
]*
|
||||
;
|
||||
|
||||
visible_designator_tail(struct node **pnd;)
|
||||
{
|
||||
register struct node *nd = *pnd;
|
||||
}:
|
||||
[
|
||||
'[' { nd = dot2node(Arrsel, nd, NULLNODE); }
|
||||
expression(&(nd->nd_right))
|
||||
[
|
||||
','
|
||||
{ nd = dot2node(Arrsel, nd, NULLNODE);
|
||||
nd->nd_symb = '[';
|
||||
}
|
||||
expression(&(nd->nd_right))
|
||||
]*
|
||||
']'
|
||||
|
|
||||
'^' { nd = dot2node(Arrow, NULLNODE, nd); }
|
||||
]
|
||||
{ *pnd = nd; }
|
||||
;
|
||||
21
lang/m2/comp/f_info.h
Normal file
21
lang/m2/comp/f_info.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* F I L E D E S C R I P T O R S T R U C T U R E */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
struct f_info {
|
||||
unsigned short f_lineno;
|
||||
char *f_filename;
|
||||
char *f_workingdir;
|
||||
};
|
||||
|
||||
extern struct f_info file_info;
|
||||
#define LineNumber file_info.f_lineno
|
||||
#define FileName file_info.f_filename
|
||||
#define WorkingDir file_info.f_workingdir
|
||||
13
lang/m2/comp/idf.c
Normal file
13
lang/m2/comp/idf.c
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* I N S T A N T I A T I O N O F I D F P A C K A G E */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "idf.h"
|
||||
#include <idf_pkg.body>
|
||||
21
lang/m2/comp/idf.h
Normal file
21
lang/m2/comp/idf.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* U S E R D E C L A R E D P A R T O F I D F */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
struct id_u {
|
||||
int id_res;
|
||||
struct def *id_df;
|
||||
};
|
||||
|
||||
#define IDF_TYPE struct id_u
|
||||
#define id_reserved id_user.id_res
|
||||
#define id_def id_user.id_df
|
||||
|
||||
#include <idf_pkg.spec>
|
||||
12
lang/m2/comp/idlist.H
Normal file
12
lang/m2/comp/idlist.H
Normal file
@@ -0,0 +1,12 @@
|
||||
/* $Header$ */
|
||||
|
||||
#include <alloc.h>
|
||||
|
||||
/* Structure to link idf structures together
|
||||
*/
|
||||
struct id_list {
|
||||
struct id_list *next;
|
||||
struct idf *id_ptr;
|
||||
};
|
||||
|
||||
/* ALLOCDEF "id_list" */
|
||||
20
lang/m2/comp/idlist.c
Normal file
20
lang/m2/comp/idlist.c
Normal file
@@ -0,0 +1,20 @@
|
||||
static char *RcsId = "$Header$";
|
||||
|
||||
#include "idf.h"
|
||||
#include "idlist.h"
|
||||
|
||||
struct id_list *h_id_list; /* Header of free list */
|
||||
|
||||
/* FreeIdList: take a list of id_list structures and put them
|
||||
on the free list of id_list structures
|
||||
*/
|
||||
FreeIdList(p)
|
||||
struct id_list *p;
|
||||
{
|
||||
register struct id_list *q;
|
||||
|
||||
while (q = p) {
|
||||
p = p->next;
|
||||
free_id_list(q);
|
||||
}
|
||||
}
|
||||
31
lang/m2/comp/input.c
Normal file
31
lang/m2/comp/input.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* I N S T A N T I A T I O N O F I N P U T P A C K A G E */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "f_info.h"
|
||||
struct f_info file_info;
|
||||
#include "input.h"
|
||||
#include <inp_pkg.body>
|
||||
|
||||
|
||||
AtEoIF()
|
||||
{
|
||||
/* Make the unstacking of input streams noticable to the
|
||||
lexical analyzer
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
AtEoIT()
|
||||
{
|
||||
/* Make the end of the text noticable
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
18
lang/m2/comp/input.h
Normal file
18
lang/m2/comp/input.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* I N S T A N T I A T I O N O F I N P U T M O D U L E */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "inputtype.h"
|
||||
|
||||
#define INP_NPUSHBACK 2
|
||||
#define INP_TYPE struct f_info
|
||||
#define INP_VAR file_info
|
||||
|
||||
#include <inp_pkg.spec>
|
||||
88
lang/m2/comp/lookup.c
Normal file
88
lang/m2/comp/lookup.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* L O O K U P R O U T I N E S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "LLlex.h"
|
||||
#include "def.h"
|
||||
#include "idf.h"
|
||||
#include "scope.h"
|
||||
#include "node.h"
|
||||
#include "type.h"
|
||||
#include "misc.h"
|
||||
|
||||
struct def *
|
||||
lookup(id, scope, import)
|
||||
register struct idf *id;
|
||||
struct scope *scope;
|
||||
{
|
||||
/* Look up a definition of an identifier in scope "scope".
|
||||
Make the "def" list self-organizing.
|
||||
Return a pointer to its "def" structure if it exists,
|
||||
otherwise return 0.
|
||||
*/
|
||||
register struct def *df, *df1;
|
||||
|
||||
/* Look in the chain of definitions of this "id" for one with scope
|
||||
"scope".
|
||||
*/
|
||||
for (df = id->id_def, df1 = 0;
|
||||
df && df->df_scope != scope;
|
||||
df1 = df, df = df->df_next) { /* nothing */ }
|
||||
|
||||
if (df) {
|
||||
/* Found it
|
||||
*/
|
||||
if (df1) {
|
||||
/* Put the definition in front
|
||||
*/
|
||||
df1->df_next = df->df_next;
|
||||
df->df_next = id->id_def;
|
||||
id->id_def = df;
|
||||
}
|
||||
if (import) {
|
||||
while (df->df_kind == D_IMPORT) {
|
||||
assert(df->imp_def != 0);
|
||||
df = df->imp_def;
|
||||
}
|
||||
}
|
||||
}
|
||||
return df;
|
||||
}
|
||||
|
||||
struct def *
|
||||
lookfor(id, vis, give_error)
|
||||
register struct node *id;
|
||||
struct scopelist *vis;
|
||||
{
|
||||
/* Look for an identifier in the visibility range started by "vis".
|
||||
If it is not defined create a dummy definition and,
|
||||
if "give_error" is set, give an error message.
|
||||
*/
|
||||
register struct def *df;
|
||||
register struct scopelist *sc = vis;
|
||||
|
||||
while (sc) {
|
||||
df = lookup(id->nd_IDF, sc->sc_scope, 1);
|
||||
if (df) return df;
|
||||
sc = nextvisible(sc);
|
||||
}
|
||||
|
||||
if (give_error) id_not_declared(id);
|
||||
|
||||
df = MkDef(id->nd_IDF, vis->sc_scope, D_ERROR);
|
||||
df->df_type = error_type;
|
||||
return df;
|
||||
}
|
||||
266
lang/m2/comp/main.c
Normal file
266
lang/m2/comp/main.c
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* M A I N P R O G R A M */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <system.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <alloc.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "f_info.h"
|
||||
#include "idf.h"
|
||||
#include "LLlex.h"
|
||||
#include "Lpars.h"
|
||||
#include "type.h"
|
||||
#include "def.h"
|
||||
#include "scope.h"
|
||||
#include "standards.h"
|
||||
#include "tokenname.h"
|
||||
#include "node.h"
|
||||
#include "warning.h"
|
||||
#include "SYSTEM.h"
|
||||
|
||||
int state; /* either IMPLEMENTATION or PROGRAM */
|
||||
char options[128];
|
||||
int DefinitionModule;
|
||||
char *ProgName;
|
||||
char **DEFPATH;
|
||||
int nDEF, mDEF;
|
||||
int pass_1;
|
||||
struct def *Defined;
|
||||
extern int err_occurred;
|
||||
extern int Roption;
|
||||
extern int fp_used; /* set if floating point used */
|
||||
struct node *EmptyStatement;
|
||||
|
||||
main(argc, argv)
|
||||
register char **argv;
|
||||
{
|
||||
register int Nargc = 1;
|
||||
register char **Nargv = &argv[0];
|
||||
|
||||
ProgName = *argv++;
|
||||
warning_classes = W_INITIAL;
|
||||
DEFPATH = (char **) Malloc(10 * sizeof(char *));
|
||||
mDEF = 10;
|
||||
nDEF = 1;
|
||||
|
||||
while (--argc > 0) {
|
||||
if (**argv == '-')
|
||||
DoOption((*argv++) + 1);
|
||||
else
|
||||
Nargv[Nargc++] = *argv++;
|
||||
}
|
||||
Nargv[Nargc] = 0; /* terminate the arg vector */
|
||||
if (Nargc < 2) {
|
||||
fprint(STDERR, "%s: Use a file argument\n", ProgName);
|
||||
exit(1);
|
||||
}
|
||||
exit(!Compile(Nargv[1], Nargv[2]));
|
||||
}
|
||||
|
||||
Compile(src, dst)
|
||||
char *src, *dst;
|
||||
{
|
||||
extern struct tokenname tkidf[];
|
||||
extern char *getwdir();
|
||||
|
||||
if (! InsertFile(src, (char **) 0, &src)) {
|
||||
fprint(STDERR,"%s: cannot open %s\n", ProgName, src);
|
||||
return 0;
|
||||
}
|
||||
LineNumber = 1;
|
||||
FileName = src;
|
||||
WorkingDir = getwdir(src);
|
||||
init_idf();
|
||||
InitCst();
|
||||
reserve(tkidf);
|
||||
InitScope();
|
||||
InitTypes();
|
||||
AddStandards();
|
||||
EmptyStatement = dot2leaf(Stat);
|
||||
EmptyStatement->nd_symb = ';';
|
||||
Roption = options['R'];
|
||||
#ifdef DEBUG
|
||||
if (options['l']) {
|
||||
LexScan();
|
||||
return 1;
|
||||
}
|
||||
#endif DEBUG
|
||||
open_scope(OPENSCOPE);
|
||||
GlobalVis = CurrVis;
|
||||
close_scope(0);
|
||||
C_init(word_size, pointer_size);
|
||||
if (! C_open(dst)) fatal("could not open output file");
|
||||
C_magic();
|
||||
C_ms_emx(word_size, pointer_size);
|
||||
CheckForLineDirective();
|
||||
pass_1 = 1;
|
||||
CompUnit();
|
||||
C_ms_src((int)LineNumber - 1, FileName);
|
||||
if (!err_occurred) {
|
||||
pass_1 = 0;
|
||||
C_exp(Defined->mod_vis->sc_scope->sc_name);
|
||||
WalkModule(Defined);
|
||||
if (fp_used) C_ms_flt();
|
||||
}
|
||||
C_close();
|
||||
#ifdef DEBUG
|
||||
if (options['i']) Info();
|
||||
#endif
|
||||
return ! err_occurred;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
LexScan()
|
||||
{
|
||||
register struct token *tkp = ˙
|
||||
extern char *symbol2str();
|
||||
|
||||
while (LLlex() > 0) {
|
||||
print(">>> %s ", symbol2str(tkp->tk_symb));
|
||||
switch(tkp->tk_symb) {
|
||||
|
||||
case IDENT:
|
||||
print("%s\n", tkp->TOK_IDF->id_text);
|
||||
break;
|
||||
|
||||
case INTEGER:
|
||||
print("%ld\n", tkp->TOK_INT);
|
||||
break;
|
||||
|
||||
case REAL:
|
||||
print("%s\n", tkp->TOK_REL);
|
||||
break;
|
||||
|
||||
case STRING:
|
||||
print("\"%s\"\n", tkp->TOK_STR);
|
||||
break;
|
||||
|
||||
default:
|
||||
print("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct stdproc {
|
||||
char *st_nam;
|
||||
int st_con;
|
||||
} stdproc[] = {
|
||||
{ "ABS", S_ABS },
|
||||
{ "CAP", S_CAP },
|
||||
{ "CHR", S_CHR },
|
||||
{ "FLOAT", S_FLOAT },
|
||||
{ "HIGH", S_HIGH },
|
||||
{ "HALT", S_HALT },
|
||||
{ "EXCL", S_EXCL },
|
||||
{ "DEC", S_DEC },
|
||||
{ "INC", S_INC },
|
||||
{ "VAL", S_VAL },
|
||||
{ "NEW", S_NEW },
|
||||
{ "DISPOSE", S_DISPOSE },
|
||||
{ "TRUNC", S_TRUNC },
|
||||
{ "SIZE", S_SIZE },
|
||||
{ "ORD", S_ORD },
|
||||
{ "ODD", S_ODD },
|
||||
{ "MAX", S_MAX },
|
||||
{ "MIN", S_MIN },
|
||||
{ "INCL", S_INCL },
|
||||
{ "LONG", S_LONG },
|
||||
{ "SHORT", S_SHORT },
|
||||
{ "TRUNCD", S_TRUNCD },
|
||||
{ "FLOATD", S_FLOATD },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
extern struct def *Enter();
|
||||
|
||||
AddStandards()
|
||||
{
|
||||
register struct def *df;
|
||||
register struct stdproc *p;
|
||||
static struct token nilconst = { INTEGER, 0};
|
||||
|
||||
for (p = stdproc; p->st_nam != 0; p++) {
|
||||
Enter(p->st_nam, D_PROCEDURE, std_type, p->st_con);
|
||||
}
|
||||
|
||||
EnterType("CHAR", char_type);
|
||||
EnterType("INTEGER", int_type);
|
||||
EnterType("LONGINT", longint_type);
|
||||
EnterType("REAL", real_type);
|
||||
EnterType("LONGREAL", longreal_type);
|
||||
EnterType("BOOLEAN", bool_type);
|
||||
EnterType("CARDINAL", card_type);
|
||||
df = Enter("NIL", D_CONST, address_type, 0);
|
||||
df->con_const = nilconst;
|
||||
|
||||
EnterType("PROC", construct_type(T_PROCEDURE, NULLTYPE));
|
||||
EnterType("BITSET", bitset_type);
|
||||
df = Enter("TRUE", D_ENUM, bool_type, 0);
|
||||
df->enm_val = 1;
|
||||
df->enm_next = Enter("FALSE", D_ENUM, bool_type, 0);
|
||||
df = df->enm_next;
|
||||
df->enm_val = 0;
|
||||
df->enm_next = 0;
|
||||
}
|
||||
|
||||
do_SYSTEM()
|
||||
{
|
||||
/* Simulate the reading of the SYSTEM definition module
|
||||
*/
|
||||
static char systemtext[] = SYSTEMTEXT;
|
||||
|
||||
open_scope(CLOSEDSCOPE);
|
||||
EnterType("WORD", word_type);
|
||||
EnterType("BYTE", byte_type);
|
||||
EnterType("ADDRESS",address_type);
|
||||
Enter("ADR", D_PROCEDURE, std_type, S_ADR);
|
||||
Enter("TSIZE", D_PROCEDURE, std_type, S_TSIZE);
|
||||
if (!InsertText(systemtext, sizeof(systemtext) - 1)) {
|
||||
fatal("could not insert text");
|
||||
}
|
||||
DefModule();
|
||||
close_scope(SC_CHKFORW);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
int cntlines;
|
||||
|
||||
Info()
|
||||
{
|
||||
extern int cnt_def, cnt_node, cnt_paramlist, cnt_type,
|
||||
cnt_switch_hdr, cnt_case_entry,
|
||||
cnt_scope, cnt_scopelist, cnt_tmpvar;
|
||||
|
||||
print("\
|
||||
%6d def\n%6d node\n%6d paramlist\n%6d type\n%6d switch_hdr\n\
|
||||
%6d case_entry\n%6d scope\n%6d scopelist\n%6d tmpvar\n",
|
||||
cnt_def, cnt_node, cnt_paramlist, cnt_type,
|
||||
cnt_switch_hdr, cnt_case_entry,
|
||||
cnt_scope, cnt_scopelist, cnt_tmpvar);
|
||||
print("\nNumber of lines read: %d\n", cntlines);
|
||||
}
|
||||
#endif
|
||||
|
||||
No_Mem()
|
||||
{
|
||||
fatal("out of memory");
|
||||
}
|
||||
|
||||
C_failed()
|
||||
{
|
||||
fatal("write failed");
|
||||
}
|
||||
25
lang/m2/comp/main.h
Normal file
25
lang/m2/comp/main.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* S O M E G L O B A L V A R I A B L E S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
extern char options[]; /* indicating which options were given */
|
||||
|
||||
extern int DefinitionModule;
|
||||
/* flag indicating that we are reading a definition
|
||||
module
|
||||
*/
|
||||
|
||||
extern struct def *Defined;
|
||||
/* definition structure of module defined in this
|
||||
compilation
|
||||
*/
|
||||
extern char **DEFPATH; /* search path for DEFINITION MODULE's */
|
||||
extern int mDEF, nDEF;
|
||||
extern int state; /* either IMPLEMENTATION or PROGRAM */
|
||||
26
lang/m2/comp/make.allocd
Executable file
26
lang/m2/comp/make.allocd
Executable file
@@ -0,0 +1,26 @@
|
||||
sed -e '
|
||||
s:^.*[ ]ALLOCDEF[ ].*"\(.*\)"[ ]*\([0-9][0-9]*\).*$:\
|
||||
/* allocation definitions of struct \1 */\
|
||||
extern char *st_alloc();\
|
||||
extern struct \1 *h_\1;\
|
||||
#ifdef DEBUG\
|
||||
extern int cnt_\1;\
|
||||
extern char *std_alloc();\
|
||||
#define new_\1() ((struct \1 *) std_alloc((char **)\&h_\1, sizeof(struct \1), \2, \&cnt_\1))\
|
||||
#else\
|
||||
#define new_\1() ((struct \1 *) st_alloc((char **)\&h_\1, sizeof(struct \1), \2))\
|
||||
#endif\
|
||||
#define free_\1(p) st_free(p, \&h_\1, sizeof(struct \1))\
|
||||
:' -e '
|
||||
s:^.*[ ]STATICALLOCDEF[ ].*"\(.*\)"[ ]*\([0-9][0-9]*\).*$:\
|
||||
/* allocation definitions of struct \1 */\
|
||||
extern char *st_alloc();\
|
||||
struct \1 *h_\1;\
|
||||
#ifdef DEBUG\
|
||||
int cnt_\1;\
|
||||
#define new_\1() ((struct \1 *) std_alloc((char **)\&h_\1, sizeof(struct \1), \2, \&cnt_\1))\
|
||||
#else\
|
||||
#define new_\1() ((struct \1 *) st_alloc((char **)\&h_\1, sizeof(struct \1), \2))\
|
||||
#endif\
|
||||
#define free_\1(p) st_free(p, \&h_\1, sizeof(struct \1))\
|
||||
:'
|
||||
35
lang/m2/comp/make.hfiles
Executable file
35
lang/m2/comp/make.hfiles
Executable file
@@ -0,0 +1,35 @@
|
||||
: Update Files from database
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
|
||||
case $# in
|
||||
1) ;;
|
||||
*) echo use: $0 file >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
(
|
||||
IFCOMMAND="if (<\$FN) 2>/dev/null;\
|
||||
then if cmp -s \$FN \$TMP;\
|
||||
then rm \$TMP;\
|
||||
else mv \$TMP \$FN;\
|
||||
echo update \$FN;\
|
||||
fi;\
|
||||
else mv \$TMP \$FN;\
|
||||
echo create \$FN;\
|
||||
fi"
|
||||
echo 'TMP=.uf$$'
|
||||
echo 'FN=$TMP'
|
||||
echo 'cat >$TMP <<\!EOF!'
|
||||
sed -n '/^!File:/,${
|
||||
/^$/d
|
||||
/^!File:[ ]*\(.*\)$/s@@!EOF!\
|
||||
'"$IFCOMMAND"'\
|
||||
FN=\1\
|
||||
cat >$TMP <<\\!EOF!@
|
||||
p
|
||||
}' $1
|
||||
echo '!EOF!'
|
||||
echo $IFCOMMAND
|
||||
) |
|
||||
sh
|
||||
7
lang/m2/comp/make.next
Executable file
7
lang/m2/comp/make.next
Executable file
@@ -0,0 +1,7 @@
|
||||
echo '#include "debug.h"'
|
||||
sed -n '
|
||||
s:^.*[ ]ALLOCDEF[ ].*"\(.*\)".*$:struct \1 *h_\1 = 0;\
|
||||
#ifdef DEBUG\
|
||||
int cnt_\1 = 0;\
|
||||
#endif:p
|
||||
' $*
|
||||
34
lang/m2/comp/make.tokcase
Executable file
34
lang/m2/comp/make.tokcase
Executable file
@@ -0,0 +1,34 @@
|
||||
cat <<'--EOT--'
|
||||
#include "Lpars.h"
|
||||
|
||||
char *
|
||||
symbol2str(tok)
|
||||
int tok;
|
||||
{
|
||||
static char buf[2] = { '\0', '\0' };
|
||||
|
||||
if (040 <= tok && tok < 0177) {
|
||||
buf[0] = tok;
|
||||
buf[1] = '\0';
|
||||
return buf;
|
||||
}
|
||||
switch (tok) {
|
||||
--EOT--
|
||||
sed '
|
||||
/{[A-Z]/!d
|
||||
s/.*{\(.*\),.*\(".*"\).*$/ case \1 :\
|
||||
return \2;/
|
||||
'
|
||||
cat <<'--EOT--'
|
||||
case '\n':
|
||||
case '\f':
|
||||
case '\v':
|
||||
case '\r':
|
||||
case '\t':
|
||||
buf[0] = tok;
|
||||
return buf;
|
||||
default:
|
||||
return "bad token";
|
||||
}
|
||||
}
|
||||
--EOT--
|
||||
6
lang/m2/comp/make.tokfile
Executable file
6
lang/m2/comp/make.tokfile
Executable file
@@ -0,0 +1,6 @@
|
||||
sed '
|
||||
/{[A-Z]/!d
|
||||
s/.*{//
|
||||
s/,.*//
|
||||
s/.*/%token &;/
|
||||
'
|
||||
16
lang/m2/comp/misc.H
Normal file
16
lang/m2/comp/misc.H
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* M I S C E L L A N E O U S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#define is_anon_idf(x) ((x)->id_text[0] == '#')
|
||||
#define id_not_declared(x) (not_declared("identifier", (x), ""))
|
||||
|
||||
extern struct idf
|
||||
*gen_anon_idf();
|
||||
66
lang/m2/comp/misc.c
Normal file
66
lang/m2/comp/misc.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* M I S C E L L A N E O U S R O U T I N E S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include <alloc.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
|
||||
#include "f_info.h"
|
||||
#include "misc.h"
|
||||
#include "LLlex.h"
|
||||
#include "idf.h"
|
||||
#include "node.h"
|
||||
|
||||
match_id(id1, id2)
|
||||
register struct idf *id1, *id2;
|
||||
{
|
||||
/* Check that identifiers id1 and id2 are equal. If they
|
||||
are not, check that we did'nt generate them in the
|
||||
first place, and if not, give an error message
|
||||
*/
|
||||
if (id1 != id2 && !is_anon_idf(id1) && !is_anon_idf(id2)) {
|
||||
error("name \"%s\" does not match block name \"%s\"",
|
||||
id1->id_text,
|
||||
id2->id_text
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
struct idf *
|
||||
gen_anon_idf()
|
||||
{
|
||||
/* A new idf is created out of nowhere, to serve as an
|
||||
anonymous name.
|
||||
*/
|
||||
static int name_cnt;
|
||||
char buff[100];
|
||||
char *sprint();
|
||||
|
||||
sprint(buff, "#%d in %s, line %u",
|
||||
++name_cnt, FileName, LineNumber);
|
||||
return str2idf(buff, 1);
|
||||
}
|
||||
|
||||
not_declared(what, id, where)
|
||||
char *what, *where;
|
||||
register struct node *id;
|
||||
{
|
||||
/* The identifier "id" is not declared. If it is not generated,
|
||||
give an error message
|
||||
*/
|
||||
if (!is_anon_idf(id->nd_IDF)) {
|
||||
node_error(id,
|
||||
"%s \"%s\" not declared%s",
|
||||
what,
|
||||
id->nd_IDF->id_text,
|
||||
where);
|
||||
}
|
||||
}
|
||||
100
lang/m2/comp/modula-2.1
Normal file
100
lang/m2/comp/modula-2.1
Normal file
@@ -0,0 +1,100 @@
|
||||
.TH MODULA\-2 1ACK
|
||||
.ad
|
||||
.SH NAME
|
||||
Modula-2 \- ACK Modula-2 compiler
|
||||
.SH SYNOPSIS
|
||||
\fBack\fR \-m\fImach\fR files
|
||||
.br
|
||||
\fImach\fR files
|
||||
.SH INTRODUCTION
|
||||
This document provides a short introduction to the use of the ACK Modula-2
|
||||
compiler. It also
|
||||
tells you where to find definition modules for "standard" modules.
|
||||
.SH FILENAMES
|
||||
Usually, a Modula-2 program consists of several definition and implementation
|
||||
modules, and one program module.
|
||||
Definition modules must reside in files with names having a ".def" extension.
|
||||
Implementation modules and program modules must reside in files having a
|
||||
".mod" extension.
|
||||
.PP
|
||||
The name of the file in which a definition module is stored must be the same as
|
||||
the module-name, apart from the extension.
|
||||
Also, in most Unix systems filenames are only 14 characters long.
|
||||
So, given an IMPORT declaration for a module called "LongModulName",
|
||||
the compiler will try to open a file called "LongModulN.def".
|
||||
The requirement does not hold for implementation or program modules,
|
||||
but is certainly recommended.
|
||||
.SH CALLING THE COMPILER
|
||||
The easiest way to do this is to let the \fIack\fR(1) program do it for you.
|
||||
So, to compile a program module "prog.mod", just call
|
||||
.DS
|
||||
\fBack\fR \-m\fImach\fR prog.mod [ objects of implementation modules ]
|
||||
or
|
||||
\fImach\fR prog.mod [ objects of implementation modules ]
|
||||
.DE
|
||||
where \fImach\fR is one of the target machines of ACK.
|
||||
.PP
|
||||
To compile an implementation module, use the \-\fBc\fR flag
|
||||
to produce a ".o" file.
|
||||
Definition modules can not be compiled; the compiler reads them when they are
|
||||
needed.
|
||||
.PP
|
||||
For more details on the \fIack\fR program see \fIack\fR(1).
|
||||
.SH DEFINITION MODULES
|
||||
"Standard" definition modules can be found in
|
||||
the directory \fB~em/lib/m2\fR.
|
||||
.PP
|
||||
When the compiler needs a definition module, it is first searched for
|
||||
in the current directory, then in the directories given to it by the
|
||||
\-\fBI\fR flag
|
||||
in the order given,
|
||||
and then in the directory mentioned above.
|
||||
.SH FLAGS
|
||||
The \fIack\fR(1) program recognizes (among others) the following
|
||||
flags, that are passed to the Modula-2 compiler:
|
||||
.IP \fB\-I\fIdirname\fR
|
||||
.br
|
||||
append \fIdirname\fR to the list of directories where definition modules
|
||||
are looked for.
|
||||
.IP \fB\-I\fP
|
||||
don't look in
|
||||
the directory \fB~em/lib/m2\fR.
|
||||
.IP \fB\-M\fP\fIn\fP
|
||||
set maximum identifier length to \fIn\fR. The minimum value of \fIn\fR
|
||||
is 14, because the keyword "IMPLEMENTATION" is that long.
|
||||
.IP \fB\-n\fR
|
||||
do not generate EM register messages.
|
||||
The user-declared variables will not be stored into registers on the target
|
||||
machine.
|
||||
.IP \fB\-L\fR
|
||||
do not generate the EM \fBfil\fR and \fBlin\fR instructions that enable
|
||||
an interpreter to keep track of the current location in the source code.
|
||||
.IP \fB\-w\fR\fIclasses\fR
|
||||
suppress warning messages whose class is a member of \fIclasses\fR.
|
||||
Currently, there are three classes: \fBO\fR, indicating old-flashioned use,
|
||||
\fBW\fR, indicating "ordinary" warnings, and \fBR\fR, indicating
|
||||
restricted Modula-2.
|
||||
If no \fIclasses\fR are given, all warnings are suppressed.
|
||||
By default, warnings in class \fBO\fR and \fBW\fR are given.
|
||||
.IP \fB\-W\fR\fIclasses\fR
|
||||
allow for warning messages whose class is a member of \fIclasses\fR.
|
||||
.IP \fB\-x\fR
|
||||
make all procedure names global, so that \fIadb\fR(1) understands them.
|
||||
.IP \fB\-Xs\fR
|
||||
make INTEGER ranges symmetric, t.i., MIN(INTEGER) = - MAX(INTEGER).
|
||||
This is useful for interpreters that use the "real" MIN(INTEGER) to
|
||||
indicate "undefined".
|
||||
.IP \fB\-Xi\fR\fIn\fR
|
||||
set maximum number of bits in a set to \fIn\fP.
|
||||
When not used, a default value is retained.
|
||||
.LP
|
||||
.SH SEE ALSO
|
||||
\fIack\fR(1), \fIem_m2\fR(6)
|
||||
.SH FILES
|
||||
.IR ~em/lib/em_m2 :
|
||||
binary of the Modula-2 compiler.
|
||||
.SH DIAGNOSTICS
|
||||
All warning and error messages are written on standard error output.
|
||||
.SH REMARKS
|
||||
Debugging and profiling facilities may be present during the development
|
||||
of \fIem_m2\fP.
|
||||
4
lang/m2/comp/nmclash.c
Normal file
4
lang/m2/comp/nmclash.c
Normal file
@@ -0,0 +1,4 @@
|
||||
/* Accepted if many characters of long names are significant */
|
||||
abcdefghijklmnopr() { }
|
||||
abcdefghijklmnopq() { }
|
||||
main() { }
|
||||
55
lang/m2/comp/node.H
Normal file
55
lang/m2/comp/node.H
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* N O D E O F A N A B S T R A C T P A R S E T R E E */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
struct node {
|
||||
struct node *nd_left;
|
||||
struct node *nd_right;
|
||||
int nd_class; /* kind of node */
|
||||
#define Value 0 /* constant */
|
||||
#define Arrsel 1 /* array selection */
|
||||
#define Oper 2 /* binary operator */
|
||||
#define Uoper 3 /* unary operator */
|
||||
#define Arrow 4 /* ^ construction */
|
||||
#define Call 5 /* cast or procedure - or function call */
|
||||
#define Name 6 /* an identifier */
|
||||
#define Set 7 /* a set constant */
|
||||
#define Xset 8 /* a set */
|
||||
#define Def 9 /* an identified name */
|
||||
#define Stat 10 /* a statement */
|
||||
#define Link 11
|
||||
#define Option 12
|
||||
/* do NOT change the order or the numbers!!! */
|
||||
struct type *nd_type; /* type of this node */
|
||||
struct token nd_token;
|
||||
#define nd_set nd_token.tk_data.tk_set
|
||||
#define nd_def nd_token.tk_data.tk_def
|
||||
#define nd_lab nd_token.tk_data.tk_lab
|
||||
#define nd_symb nd_token.tk_symb
|
||||
#define nd_lineno nd_token.tk_lineno
|
||||
#define nd_IDF nd_token.TOK_IDF
|
||||
#define nd_STR nd_token.TOK_STR
|
||||
#define nd_SLE nd_token.TOK_SLE
|
||||
#define nd_INT nd_token.TOK_INT
|
||||
#define nd_REL nd_token.TOK_REL
|
||||
};
|
||||
|
||||
/* ALLOCDEF "node" 50 */
|
||||
|
||||
extern struct node *MkNode(), *MkLeaf(), *dot2node(), *dot2leaf();
|
||||
|
||||
#define NULLNODE ((struct node *) 0)
|
||||
|
||||
#define HASSELECTORS 002
|
||||
#define VARIABLE 004
|
||||
#define VALUE 010
|
||||
|
||||
#define IsCast(lnd) ((lnd)->nd_class == Def && is_type((lnd)->nd_def))
|
||||
#define IsProcCall(lnd) ((lnd)->nd_type->tp_fund == T_PROCEDURE)
|
||||
117
lang/m2/comp/node.c
Normal file
117
lang/m2/comp/node.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* N O D E O F A N A B S T R A C T P A R S E T R E E */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <em_label.h>
|
||||
#include <em_arith.h>
|
||||
#include <alloc.h>
|
||||
#include <system.h>
|
||||
|
||||
#include "LLlex.h"
|
||||
#include "def.h"
|
||||
#include "type.h"
|
||||
#include "node.h"
|
||||
|
||||
struct node *
|
||||
MkNode(class, left, right, token)
|
||||
struct node *left, *right;
|
||||
struct token *token;
|
||||
{
|
||||
/* Create a node and initialize it with the given parameters
|
||||
*/
|
||||
register struct node *nd = new_node();
|
||||
|
||||
nd->nd_left = left;
|
||||
nd->nd_right = right;
|
||||
nd->nd_token = *token;
|
||||
nd->nd_class = class;
|
||||
return nd;
|
||||
}
|
||||
|
||||
struct node *
|
||||
dot2node(class, left, right)
|
||||
struct node *left, *right;
|
||||
{
|
||||
return MkNode(class, left, right, &dot);
|
||||
}
|
||||
|
||||
struct node *
|
||||
MkLeaf(class, token)
|
||||
struct token *token;
|
||||
{
|
||||
register struct node *nd = new_node();
|
||||
|
||||
nd->nd_token = *token;
|
||||
nd->nd_class = class;
|
||||
return nd;
|
||||
}
|
||||
|
||||
struct node *
|
||||
dot2leaf(class)
|
||||
{
|
||||
return MkLeaf(class, &dot);
|
||||
}
|
||||
|
||||
FreeNode(nd)
|
||||
register struct node *nd;
|
||||
{
|
||||
/* Put nodes that are no longer needed back onto the free
|
||||
list
|
||||
*/
|
||||
if (!nd) return;
|
||||
FreeNode(nd->nd_left);
|
||||
FreeNode(nd->nd_right);
|
||||
free_node(nd);
|
||||
}
|
||||
|
||||
NodeCrash(expp)
|
||||
struct node *expp;
|
||||
{
|
||||
crash("Illegal node %d", expp->nd_class);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
extern char *symbol2str();
|
||||
|
||||
indnt(lvl)
|
||||
{
|
||||
while (lvl--) {
|
||||
print(" ");
|
||||
}
|
||||
}
|
||||
|
||||
printnode(nd, lvl)
|
||||
register struct node *nd;
|
||||
{
|
||||
indnt(lvl);
|
||||
print("Class: %d; Symbol: %s\n", nd->nd_class, symbol2str(nd->nd_symb));
|
||||
if (nd->nd_type) {
|
||||
indnt(lvl);
|
||||
print("Type: ");
|
||||
DumpType(nd->nd_type);
|
||||
print("\n");
|
||||
}
|
||||
}
|
||||
|
||||
PrNode(nd, lvl)
|
||||
register struct node *nd;
|
||||
{
|
||||
if (! nd) {
|
||||
indnt(lvl); print("<nilnode>\n");
|
||||
return;
|
||||
}
|
||||
printnode(nd, lvl);
|
||||
PrNode(nd->nd_left, lvl + 1);
|
||||
PrNode(nd->nd_right, lvl + 1);
|
||||
}
|
||||
#endif DEBUG
|
||||
240
lang/m2/comp/options.c
Normal file
240
lang/m2/comp/options.c
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* U S E R O P T I O N - H A N D L I N G */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "idfsize.h"
|
||||
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <alloc.h>
|
||||
|
||||
#include "type.h"
|
||||
#include "main.h"
|
||||
#include "warning.h"
|
||||
|
||||
#define MINIDFSIZE 14
|
||||
|
||||
#if MINIDFSIZE < 14
|
||||
You fouled up! MINIDFSIZE has to be at least 14 or the compiler will not
|
||||
recognize some keywords!
|
||||
#endif
|
||||
|
||||
extern int idfsize;
|
||||
static int ndirs = 1;
|
||||
int warning_classes;
|
||||
|
||||
DoOption(text)
|
||||
register char *text;
|
||||
{
|
||||
switch(*text++) {
|
||||
|
||||
case '-':
|
||||
options[*text]++; /* debug options etc. */
|
||||
break;
|
||||
|
||||
case 'L': /* no fil/lin */
|
||||
case 'R': /* no range checks */
|
||||
case 'n': /* no register messages */
|
||||
case 'x': /* every name global */
|
||||
case 's': /* symmetric: MIN(INTEGER) = -MAX(INTEGER) */
|
||||
options[text[-1]]++;
|
||||
break;
|
||||
|
||||
case 'i': /* # of bits in set */
|
||||
{
|
||||
char *t = text;
|
||||
int val;
|
||||
extern int maxset;
|
||||
|
||||
val = txt2int(&t);
|
||||
if (val <= 0 || *t) {
|
||||
error("bad -i flag; use -i<num>");
|
||||
}
|
||||
else maxset = val;
|
||||
break;
|
||||
}
|
||||
case 'w':
|
||||
if (*text) {
|
||||
while (*text) {
|
||||
switch(*text++) {
|
||||
case 'O':
|
||||
warning_classes &= ~W_OLDFASHIONED;
|
||||
break;
|
||||
case 'R':
|
||||
warning_classes &= ~W_STRICT;
|
||||
break;
|
||||
case 'W':
|
||||
warning_classes &= ~W_ORDINARY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else warning_classes = 0;
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
if (*text) {
|
||||
while (*text) {
|
||||
switch(*text++) {
|
||||
case 'O':
|
||||
warning_classes |= W_OLDFASHIONED;
|
||||
break;
|
||||
case 'R':
|
||||
warning_classes |= W_STRICT;
|
||||
break;
|
||||
case 'W':
|
||||
warning_classes |= W_ORDINARY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else warning_classes = W_OLDFASHIONED|W_STRICT|W_ORDINARY;
|
||||
break;
|
||||
|
||||
case 'M': { /* maximum identifier length */
|
||||
char *t = text; /* because &text is illegal */
|
||||
|
||||
idfsize = txt2int(&t);
|
||||
if (*t || idfsize <= 0)
|
||||
fatal("malformed -M option");
|
||||
if (idfsize > IDFSIZE) {
|
||||
idfsize = IDFSIZE;
|
||||
warning(W_ORDINARY,"maximum identifier length is %d", IDFSIZE);
|
||||
}
|
||||
if (idfsize < MINIDFSIZE) {
|
||||
warning(W_ORDINARY, "minimum identifier length is %d", MINIDFSIZE);
|
||||
idfsize = MINIDFSIZE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'I' :
|
||||
if (*text) {
|
||||
register int i;
|
||||
register char *new = text;
|
||||
|
||||
if (++nDEF > mDEF) {
|
||||
char **n = (char **)
|
||||
Malloc((unsigned)((10+mDEF)*sizeof(char *)));
|
||||
|
||||
for (i = 0; i < mDEF; i++) {
|
||||
n[i] = DEFPATH[i];
|
||||
}
|
||||
free((char *) DEFPATH);
|
||||
DEFPATH = n;
|
||||
mDEF += 10;
|
||||
}
|
||||
|
||||
i = ndirs++;
|
||||
while (new) {
|
||||
register char *tmp = DEFPATH[i];
|
||||
|
||||
DEFPATH[i++] = new;
|
||||
new = tmp;
|
||||
}
|
||||
}
|
||||
else DEFPATH[ndirs] = 0;
|
||||
break;
|
||||
|
||||
case 'V' : /* set object sizes and alignment requirements */
|
||||
{
|
||||
register int size;
|
||||
register int align;
|
||||
char c;
|
||||
char *t;
|
||||
|
||||
while (c = *text++) {
|
||||
char *strindex();
|
||||
|
||||
t = text;
|
||||
size = txt2int(&t);
|
||||
align = 0;
|
||||
if (*(text = t) == '.') {
|
||||
t = text + 1;
|
||||
align = txt2int(&t);
|
||||
text = t;
|
||||
}
|
||||
if (! strindex("wislfdpS", c)) {
|
||||
error("-V: bad type indicator %c\n", c);
|
||||
}
|
||||
if (size != 0) switch (c) {
|
||||
|
||||
case 'w': /* word */
|
||||
word_size = size;
|
||||
dword_size = 2 * size;
|
||||
break;
|
||||
case 'i': /* int */
|
||||
int_size = size;
|
||||
break;
|
||||
case 's': /* short (subranges) */
|
||||
short_size = size;
|
||||
break;
|
||||
case 'l': /* longint */
|
||||
long_size = size;
|
||||
break;
|
||||
case 'f': /* real */
|
||||
float_size = size;
|
||||
break;
|
||||
case 'd': /* longreal */
|
||||
double_size = size;
|
||||
break;
|
||||
case 'p': /* pointer */
|
||||
pointer_size = size;
|
||||
break;
|
||||
}
|
||||
if (align != 0) switch (c) {
|
||||
|
||||
case 'w': /* word */
|
||||
word_align = align;
|
||||
break;
|
||||
case 'i': /* int */
|
||||
int_align = align;
|
||||
break;
|
||||
case 's': /* short (subranges) */
|
||||
short_align = align;
|
||||
break;
|
||||
case 'l': /* longint */
|
||||
long_align = align;
|
||||
break;
|
||||
case 'f': /* real */
|
||||
float_align = align;
|
||||
break;
|
||||
case 'd': /* longreal */
|
||||
double_align = align;
|
||||
break;
|
||||
case 'p': /* pointer */
|
||||
pointer_align = align;
|
||||
break;
|
||||
case 'S': /* initial record alignment */
|
||||
struct_align = align;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
txt2int(tp)
|
||||
register char **tp;
|
||||
{
|
||||
/* the integer pointed to by *tp is read, while increasing
|
||||
*tp; the resulting value is yielded.
|
||||
*/
|
||||
register int val = 0;
|
||||
register int ch;
|
||||
|
||||
while (ch = **tp, ch >= '0' && ch <= '9') {
|
||||
val = val * 10 + ch - '0';
|
||||
(*tp)++;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
4
lang/m2/comp/param.h
Normal file
4
lang/m2/comp/param.h
Normal file
@@ -0,0 +1,4 @@
|
||||
/* $Header$ */
|
||||
|
||||
#define IDFSIZE 256
|
||||
#define NUMSIZE 256
|
||||
144
lang/m2/comp/print.c
Normal file
144
lang/m2/comp/print.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/* P R I N T R O U T I N E S */
|
||||
|
||||
#include <system.h>
|
||||
#include <em_arith.h>
|
||||
|
||||
#define SSIZE 1024 /* string-buffer size for print routines */
|
||||
|
||||
char *long2str();
|
||||
|
||||
doprnt(fp, fmt, argp)
|
||||
File *fp;
|
||||
char *fmt;
|
||||
int argp[];
|
||||
{
|
||||
char buf[SSIZE];
|
||||
|
||||
sys_write(fp, buf, format(buf, fmt, (char *)argp));
|
||||
}
|
||||
|
||||
/*VARARGS1*/
|
||||
printf(fmt, args)
|
||||
char *fmt;
|
||||
char args;
|
||||
{
|
||||
char buf[SSIZE];
|
||||
|
||||
sys_write(STDOUT, buf, format(buf, fmt, &args));
|
||||
}
|
||||
|
||||
/*VARARGS1*/
|
||||
fprintf(fp, fmt, args)
|
||||
File *fp;
|
||||
char *fmt;
|
||||
char args;
|
||||
{
|
||||
char buf[SSIZE];
|
||||
|
||||
sys_write(fp, buf, format(buf, fmt, &args));
|
||||
}
|
||||
|
||||
/*VARARGS1*/
|
||||
char *
|
||||
sprintf(buf, fmt, args)
|
||||
char *buf, *fmt;
|
||||
char args;
|
||||
{
|
||||
buf[format(buf, fmt, &args)] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
int
|
||||
format(buf, fmt, argp)
|
||||
char *buf, *fmt;
|
||||
char *argp;
|
||||
{
|
||||
register char *pf = fmt, *pa = argp;
|
||||
register char *pb = buf;
|
||||
|
||||
while (*pf) {
|
||||
if (*pf == '%') {
|
||||
register int width, base, pad, npad;
|
||||
char *arg;
|
||||
char cbuf[2];
|
||||
char *badformat = "<bad format>";
|
||||
|
||||
/* get padder */
|
||||
if (*++pf == '0') {
|
||||
pad = '0';
|
||||
++pf;
|
||||
}
|
||||
else
|
||||
pad = ' ';
|
||||
|
||||
/* get width */
|
||||
width = 0;
|
||||
while (*pf >= '0' && *pf <= '9')
|
||||
width = 10 * width + *pf++ - '0';
|
||||
|
||||
/* get text and move pa */
|
||||
if (*pf == 's') {
|
||||
arg = *(char **)pa;
|
||||
pa += sizeof(char *);
|
||||
}
|
||||
else
|
||||
if (*pf == 'c') {
|
||||
cbuf[0] = * (char *) pa;
|
||||
cbuf[1] = '\0';
|
||||
pa += sizeof(int);
|
||||
arg = &cbuf[0];
|
||||
}
|
||||
else
|
||||
if (*pf == 'l') {
|
||||
/* alignment ??? */
|
||||
if (base = integral(*++pf)) {
|
||||
arg = long2str(*(long *)pa, base);
|
||||
pa += sizeof(long);
|
||||
}
|
||||
else {
|
||||
pf--;
|
||||
arg = badformat;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (base = integral(*pf)) {
|
||||
arg = long2str((long)*(int *)pa, base);
|
||||
pa += sizeof(int);
|
||||
}
|
||||
else
|
||||
if (*pf == '%')
|
||||
arg = "%";
|
||||
else
|
||||
arg = badformat;
|
||||
|
||||
npad = width - strlen(arg);
|
||||
|
||||
while (npad-- > 0)
|
||||
*pb++ = pad;
|
||||
|
||||
while (*pb++ = *arg++);
|
||||
pb--;
|
||||
pf++;
|
||||
}
|
||||
else
|
||||
*pb++ = *pf++;
|
||||
}
|
||||
return pb - buf;
|
||||
}
|
||||
|
||||
integral(c)
|
||||
{
|
||||
switch (c) {
|
||||
case 'b':
|
||||
return -2;
|
||||
case 'd':
|
||||
return 10;
|
||||
case 'o':
|
||||
return -8;
|
||||
case 'u':
|
||||
return -10;
|
||||
case 'x':
|
||||
return -16;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
245
lang/m2/comp/program.g
Normal file
245
lang/m2/comp/program.g
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* O V E R A L L S T R U C T U R E */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
{
|
||||
#include "debug.h"
|
||||
|
||||
#include <alloc.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "idf.h"
|
||||
#include "LLlex.h"
|
||||
#include "scope.h"
|
||||
#include "def.h"
|
||||
#include "type.h"
|
||||
#include "node.h"
|
||||
#include "f_info.h"
|
||||
#include "warning.h"
|
||||
|
||||
}
|
||||
/*
|
||||
The grammar as given by Wirth is already almost LL(1); the
|
||||
main problem is that the full form of a qualified designator
|
||||
may be:
|
||||
[ module_ident '.' ]* IDENT [ '.' field_ident ]*
|
||||
which is quite confusing to an LL(1) parser. Rather than
|
||||
resorting to context-sensitive techniques, I have decided
|
||||
to render this as:
|
||||
IDENT [ '.' IDENT ]*
|
||||
on the grounds that it is quite natural to consider the first
|
||||
IDENT to be the name of the object and regard the others as
|
||||
field identifiers.
|
||||
*/
|
||||
|
||||
%lexical LLlex;
|
||||
|
||||
%start CompUnit, CompilationUnit;
|
||||
%start DefModule, DefinitionModule;
|
||||
|
||||
ModuleDeclaration
|
||||
{
|
||||
register struct def *df;
|
||||
struct node *exportlist = 0;
|
||||
int qualified;
|
||||
} :
|
||||
MODULE IDENT { df = DefineLocalModule(dot.TOK_IDF); }
|
||||
priority(df)
|
||||
';'
|
||||
import(1)*
|
||||
export(&qualified, &exportlist)?
|
||||
block(&(df->mod_body))
|
||||
IDENT { if (exportlist) {
|
||||
EnterExportList(exportlist, qualified);
|
||||
}
|
||||
close_scope(SC_CHKFORW|SC_CHKPROC|SC_REVERSE);
|
||||
match_id(df->df_idf, dot.TOK_IDF);
|
||||
}
|
||||
;
|
||||
|
||||
priority(register struct def *df;):
|
||||
[
|
||||
'[' ConstExpression(&(df->mod_priority)) ']'
|
||||
{ if (!(df->mod_priority->nd_type->tp_fund &
|
||||
T_CARDINAL)) {
|
||||
node_error(df->mod_priority,
|
||||
"illegal priority");
|
||||
}
|
||||
}
|
||||
|
|
||||
{ df->mod_priority = 0; }
|
||||
]
|
||||
;
|
||||
|
||||
export(int *QUALflag; struct node **ExportList;):
|
||||
EXPORT
|
||||
[
|
||||
QUALIFIED
|
||||
{ *QUALflag = D_QEXPORTED; }
|
||||
|
|
||||
{ *QUALflag = D_EXPORTED; }
|
||||
]
|
||||
IdentList(ExportList) ';'
|
||||
;
|
||||
|
||||
import(int local;)
|
||||
{
|
||||
struct node *ImportList;
|
||||
register struct node *FromId = 0;
|
||||
register struct def *df;
|
||||
extern struct def *GetDefinitionModule();
|
||||
} :
|
||||
[ FROM
|
||||
IDENT { FromId = dot2leaf(Name);
|
||||
if (local) df = lookfor(FromId,enclosing(CurrVis),0);
|
||||
else df = GetDefinitionModule(dot.TOK_IDF, 1);
|
||||
}
|
||||
]?
|
||||
IMPORT IdentList(&ImportList) ';'
|
||||
/*
|
||||
When parsing a global module, this is the place where we must
|
||||
read already compiled definition modules.
|
||||
If the FROM clause is present, the identifier in it is a module
|
||||
name, otherwise the names in the import list are module names.
|
||||
*/
|
||||
{ if (FromId) {
|
||||
EnterFromImportList(ImportList, df, FromId);
|
||||
}
|
||||
else EnterImportList(ImportList, local);
|
||||
}
|
||||
;
|
||||
|
||||
DefinitionModule
|
||||
{
|
||||
register struct def *df;
|
||||
struct node *exportlist;
|
||||
int dummy;
|
||||
extern struct idf *DefId;
|
||||
extern int ForeignFlag;
|
||||
} :
|
||||
DEFINITION
|
||||
MODULE IDENT { df = define(dot.TOK_IDF, GlobalScope, D_MODULE);
|
||||
df->df_flags |= D_BUSY;
|
||||
df->df_flags |= ForeignFlag;
|
||||
if (!Defined) Defined = df;
|
||||
CurrentScope->sc_definedby = df;
|
||||
if (df->df_idf != DefId) {
|
||||
error("DEFINITION MODULE name is \"%s\", not \"%s\"",
|
||||
df->df_idf->id_text, DefId->id_text);
|
||||
}
|
||||
CurrentScope->sc_name = df->df_idf->id_text;
|
||||
df->mod_vis = CurrVis;
|
||||
df->df_type = standard_type(T_RECORD, 1, (arith) 1);
|
||||
df->df_type->rec_scope = df->mod_vis->sc_scope;
|
||||
DefinitionModule++;
|
||||
}
|
||||
';'
|
||||
import(0)*
|
||||
[
|
||||
export(&dummy, &exportlist)
|
||||
/* New Modula-2 does not have export lists in definition
|
||||
modules. Issue a warning.
|
||||
*/
|
||||
{
|
||||
node_warning(exportlist, W_OLDFASHIONED, "export list in definition module ignored");
|
||||
FreeNode(exportlist);
|
||||
}
|
||||
|
|
||||
/* empty */
|
||||
]
|
||||
definition* END IDENT
|
||||
{ register struct def *df1 = CurrentScope->sc_def;
|
||||
while (df1) {
|
||||
/* Make all definitions "QUALIFIED EXPORT" */
|
||||
df1->df_flags |= D_QEXPORTED;
|
||||
df1 = df1->df_nextinscope;
|
||||
}
|
||||
DefinitionModule--;
|
||||
match_id(df->df_idf, dot.TOK_IDF);
|
||||
df->df_flags &= ~D_BUSY;
|
||||
}
|
||||
'.'
|
||||
;
|
||||
|
||||
definition
|
||||
{
|
||||
register struct def *df;
|
||||
struct def *dummy;
|
||||
} :
|
||||
CONST [ %persistent ConstantDeclaration ';' ]*
|
||||
|
|
||||
TYPE
|
||||
[ %persistent
|
||||
IDENT { df = define(dot.TOK_IDF, CurrentScope, D_TYPE); }
|
||||
[ '=' type(&(df->df_type))
|
||||
| /* empty */
|
||||
/*
|
||||
Here, the exported type has a hidden implementation.
|
||||
The export is said to be opaque.
|
||||
It is restricted to pointer types.
|
||||
*/
|
||||
{ df->df_kind = D_HIDDEN;
|
||||
df->df_type = construct_type(T_HIDDEN, NULLTYPE);
|
||||
}
|
||||
]
|
||||
';'
|
||||
]*
|
||||
|
|
||||
VAR [ %persistent VariableDeclaration ';' ]*
|
||||
|
|
||||
ProcedureHeading(&dummy, D_PROCHEAD)
|
||||
';'
|
||||
;
|
||||
|
||||
ProgramModule
|
||||
{
|
||||
extern struct def *GetDefinitionModule();
|
||||
register struct def *df;
|
||||
} :
|
||||
MODULE
|
||||
IDENT { if (state == IMPLEMENTATION) {
|
||||
df = GetDefinitionModule(dot.TOK_IDF, 0);
|
||||
CurrVis = df->mod_vis;
|
||||
RemoveImports(&(CurrentScope->sc_def));
|
||||
}
|
||||
else {
|
||||
Defined = df = define(dot.TOK_IDF, GlobalScope, D_MODULE);
|
||||
open_scope(CLOSEDSCOPE);
|
||||
df->mod_vis = CurrVis;
|
||||
CurrentScope->sc_name = "_M2M";
|
||||
CurrentScope->sc_definedby = df;
|
||||
}
|
||||
}
|
||||
priority(df)
|
||||
';' import(0)*
|
||||
block(&(df->mod_body)) IDENT
|
||||
{ close_scope(SC_CHKFORW|SC_CHKPROC|SC_REVERSE);
|
||||
match_id(df->df_idf, dot.TOK_IDF);
|
||||
}
|
||||
'.'
|
||||
;
|
||||
|
||||
Module:
|
||||
DEFINITION
|
||||
{ fatal("Compiling a definition module"); }
|
||||
| %default
|
||||
[
|
||||
IMPLEMENTATION { state = IMPLEMENTATION; }
|
||||
|
|
||||
/* empty */ { state = PROGRAM; }
|
||||
]
|
||||
ProgramModule
|
||||
;
|
||||
|
||||
CompilationUnit:
|
||||
Module
|
||||
;
|
||||
238
lang/m2/comp/scope.C
Normal file
238
lang/m2/comp/scope.C
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* S C O P E M E C H A N I S M */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <alloc.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
|
||||
#include "LLlex.h"
|
||||
#include "idf.h"
|
||||
#include "scope.h"
|
||||
#include "type.h"
|
||||
#include "def.h"
|
||||
#include "node.h"
|
||||
|
||||
struct scope *PervasiveScope;
|
||||
struct scopelist *CurrVis, *GlobalVis;
|
||||
extern int proclevel;
|
||||
static struct scopelist *PervVis;
|
||||
extern char options[];
|
||||
|
||||
/* STATICALLOCDEF "scope" 10 */
|
||||
|
||||
/* STATICALLOCDEF "scopelist" 10 */
|
||||
|
||||
open_scope(scopetype)
|
||||
{
|
||||
/* Open a scope that is either open (automatic imports) or closed.
|
||||
*/
|
||||
register struct scope *sc = new_scope();
|
||||
register struct scopelist *ls = new_scopelist();
|
||||
|
||||
assert(scopetype == OPENSCOPE || scopetype == CLOSEDSCOPE);
|
||||
|
||||
sc->sc_scopeclosed = scopetype == CLOSEDSCOPE;
|
||||
sc->sc_level = proclevel;
|
||||
ls->sc_scope = sc;
|
||||
ls->sc_encl = CurrVis;
|
||||
if (scopetype == OPENSCOPE) {
|
||||
ls->sc_next = ls->sc_encl;
|
||||
}
|
||||
else ls->sc_next = PervVis;
|
||||
CurrVis = ls;
|
||||
}
|
||||
|
||||
struct scope *
|
||||
open_and_close_scope(scopetype)
|
||||
{
|
||||
struct scope *sc;
|
||||
|
||||
open_scope(scopetype);
|
||||
sc = CurrentScope;
|
||||
close_scope(0);
|
||||
return sc;
|
||||
}
|
||||
|
||||
InitScope()
|
||||
{
|
||||
register struct scope *sc = new_scope();
|
||||
register struct scopelist *ls = new_scopelist();
|
||||
|
||||
sc->sc_scopeclosed = 0;
|
||||
sc->sc_def = 0;
|
||||
sc->sc_level = proclevel;
|
||||
PervasiveScope = sc;
|
||||
ls->sc_next = 0;
|
||||
ls->sc_encl = 0;
|
||||
ls->sc_scope = PervasiveScope;
|
||||
PervVis = ls;
|
||||
CurrVis = ls;
|
||||
}
|
||||
|
||||
STATIC
|
||||
chk_proc(df)
|
||||
register struct def *df;
|
||||
{
|
||||
/* Called at scope closing. Check all definitions, and if one
|
||||
is a D_PROCHEAD, the procedure was not defined.
|
||||
Also check that hidden types are defined.
|
||||
*/
|
||||
while (df) {
|
||||
if (df->df_kind == D_HIDDEN) {
|
||||
error("hidden type \"%s\" not declared",
|
||||
df->df_idf->id_text);
|
||||
}
|
||||
else if (df->df_kind == D_PROCHEAD) {
|
||||
/* A not defined procedure
|
||||
*/
|
||||
error("procedure \"%s\" not defined",
|
||||
df->df_idf->id_text);
|
||||
FreeNode(df->for_node);
|
||||
}
|
||||
df = df->df_nextinscope;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
chk_forw(pdf)
|
||||
struct def **pdf;
|
||||
{
|
||||
/* Called at scope close. Look for all forward definitions and
|
||||
if the scope was a closed scope, give an error message for
|
||||
them, and otherwise move them to the enclosing scope.
|
||||
*/
|
||||
register struct def *df;
|
||||
|
||||
while (df = *pdf) {
|
||||
if (df->df_kind == D_FORWTYPE) {
|
||||
register struct def *df1 = df;
|
||||
register struct node *nd = df->df_forw_node;
|
||||
|
||||
*pdf = df->df_nextinscope;
|
||||
RemoveFromIdList(df);
|
||||
df = lookfor(nd, CurrVis, 1);
|
||||
if (! df->df_kind & (D_ERROR|D_FTYPE|D_TYPE)) {
|
||||
node_error(nd, "\"%s\" is not a type", df1->df_idf->id_text);
|
||||
}
|
||||
while (nd) {
|
||||
nd->nd_type->tp_next = df->df_type;
|
||||
nd = nd->nd_right;
|
||||
}
|
||||
FreeNode(df1->df_forw_node);
|
||||
free_def(df1);
|
||||
continue;
|
||||
}
|
||||
else if (df->df_kind == D_FTYPE) {
|
||||
register struct node *nd = df->df_forw_node;
|
||||
|
||||
df->df_kind = D_TYPE;
|
||||
while (nd) {
|
||||
nd->nd_type->tp_next = df->df_type;
|
||||
nd = nd->nd_right;
|
||||
}
|
||||
FreeNode(df->df_forw_node);
|
||||
}
|
||||
else if (df->df_kind & (D_FORWARD|D_FORWMODULE)) {
|
||||
/* These definitions must be found in
|
||||
the enclosing closed scope, which of course
|
||||
may be the scope that is now closed!
|
||||
*/
|
||||
if (scopeclosed(CurrentScope)) {
|
||||
/* Indeed, the scope was a closed
|
||||
scope, so give error message
|
||||
*/
|
||||
node_error(df->for_node, "identifier \"%s\" not declared",
|
||||
df->df_idf->id_text);
|
||||
FreeNode(df->for_node);
|
||||
}
|
||||
else {
|
||||
/* This scope was an open scope.
|
||||
Maybe the definitions are in the
|
||||
enclosing scope?
|
||||
*/
|
||||
register struct scopelist *ls =
|
||||
nextvisible(CurrVis);
|
||||
struct def *df1 = df->df_nextinscope;
|
||||
|
||||
if (df->df_kind == D_FORWMODULE) {
|
||||
df->for_vis->sc_next = ls;
|
||||
}
|
||||
df->df_nextinscope = ls->sc_scope->sc_def;
|
||||
ls->sc_scope->sc_def = df;
|
||||
df->df_scope = ls->sc_scope;
|
||||
*pdf = df1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
pdf = &df->df_nextinscope;
|
||||
}
|
||||
}
|
||||
|
||||
Reverse(pdf)
|
||||
struct def **pdf;
|
||||
{
|
||||
/* Reverse the order in the list of definitions in a scope.
|
||||
This is neccesary because this list is built in reverse.
|
||||
Also, while we're at it, remove uninteresting definitions
|
||||
from this list.
|
||||
*/
|
||||
register struct def *df, *df1;
|
||||
#define INTERESTING D_MODULE|D_PROCEDURE|D_PROCHEAD|D_VARIABLE
|
||||
|
||||
df = 0;
|
||||
df1 = *pdf;
|
||||
|
||||
while (df1) {
|
||||
if (df1->df_kind & INTERESTING) {
|
||||
struct def *prev = df;
|
||||
|
||||
df = df1;
|
||||
df1 = df1->df_nextinscope;
|
||||
df->df_nextinscope = prev;
|
||||
}
|
||||
else df1 = df1->df_nextinscope;
|
||||
}
|
||||
*pdf = df;
|
||||
}
|
||||
|
||||
close_scope(flag)
|
||||
register int flag;
|
||||
{
|
||||
/* Close a scope. If "flag" is set, check for forward declarations,
|
||||
either POINTER declarations, or EXPORTs, or forward references
|
||||
to MODULES
|
||||
*/
|
||||
register struct scope *sc = CurrentScope;
|
||||
|
||||
assert(sc != 0);
|
||||
|
||||
if (flag) {
|
||||
DO_DEBUG(options['S'],(print("List of definitions in currently ended scope:\n"), DumpScope(sc->sc_def)));
|
||||
if (flag & SC_CHKPROC) chk_proc(sc->sc_def);
|
||||
if (flag & SC_CHKFORW) chk_forw(&(sc->sc_def));
|
||||
if (flag & SC_REVERSE) Reverse(&(sc->sc_def));
|
||||
}
|
||||
CurrVis = enclosing(CurrVis);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
DumpScope(df)
|
||||
register struct def *df;
|
||||
{
|
||||
while (df) {
|
||||
PrDef(df);
|
||||
df = df->df_nextinscope;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
53
lang/m2/comp/scope.h
Normal file
53
lang/m2/comp/scope.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* S C O P E M E C H A N I S M */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#define OPENSCOPE 0 /* Indicating an open scope */
|
||||
#define CLOSEDSCOPE 1 /* Indicating a closed scope (module) */
|
||||
|
||||
#define SC_CHKFORW 1 /* Check for forward definitions when closing
|
||||
a scope
|
||||
*/
|
||||
#define SC_CHKPROC 2 /* Check for forward procedure definitions
|
||||
when closing a scope
|
||||
*/
|
||||
#define SC_REVERSE 4 /* Reverse list of definitions, to get it
|
||||
back into original order
|
||||
*/
|
||||
|
||||
struct scope {
|
||||
/* struct scope *next; */
|
||||
char *sc_name; /* name of this scope */
|
||||
struct def *sc_def; /* list of definitions in this scope */
|
||||
arith sc_off; /* offsets of variables in this scope */
|
||||
char sc_scopeclosed; /* flag indicating closed or open scope */
|
||||
int sc_level; /* level of this scope */
|
||||
struct def *sc_definedby; /* The def structure defining this scope */
|
||||
};
|
||||
|
||||
struct scopelist {
|
||||
struct scopelist *sc_next;
|
||||
struct scope *sc_scope;
|
||||
struct scopelist *sc_encl;
|
||||
};
|
||||
|
||||
extern struct scope
|
||||
*PervasiveScope;
|
||||
|
||||
extern struct scopelist
|
||||
*CurrVis, *GlobalVis;
|
||||
|
||||
#define CurrentScope (CurrVis->sc_scope)
|
||||
#define GlobalScope (GlobalVis->sc_scope)
|
||||
#define enclosing(x) ((x)->sc_encl)
|
||||
#define scopeclosed(x) ((x)->sc_scopeclosed)
|
||||
#define nextvisible(x) ((x)->sc_next) /* use with scopelists */
|
||||
|
||||
struct scope *open_and_close_scope();
|
||||
41
lang/m2/comp/standards.h
Normal file
41
lang/m2/comp/standards.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* S T A N D A R D P R O C E D U R E S A N D F U N C T I O N S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#define S_ABS 1
|
||||
#define S_CAP 2
|
||||
#define S_CHR 3
|
||||
#define S_DEC 4
|
||||
#define S_EXCL 5
|
||||
#define S_FLOAT 6
|
||||
#define S_HALT 7
|
||||
#define S_HIGH 8
|
||||
#define S_INC 9
|
||||
#define S_INCL 10
|
||||
#define S_MAX 11
|
||||
#define S_MIN 12
|
||||
#define S_ODD 13
|
||||
#define S_ORD 14
|
||||
#define S_SIZE 15
|
||||
#define S_TRUNC 16
|
||||
#define S_VAL 17
|
||||
#define S_NEW 18
|
||||
#define S_DISPOSE 19
|
||||
#define S_LONG 20
|
||||
#define S_SHORT 21
|
||||
#define S_TRUNCD 22
|
||||
#define S_FLOATD 23
|
||||
|
||||
/* Standard procedures and functions defined in the SYSTEM module ... */
|
||||
|
||||
#define S_ADR 50
|
||||
#define S_TSIZE 51
|
||||
#define S_NEWPROCESS 52
|
||||
#define S_TRANSFER 53
|
||||
295
lang/m2/comp/statement.g
Normal file
295
lang/m2/comp/statement.g
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* S T A T E M E N T S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
{
|
||||
#include <assert.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
|
||||
#include "idf.h"
|
||||
#include "LLlex.h"
|
||||
#include "scope.h"
|
||||
#include "def.h"
|
||||
#include "type.h"
|
||||
#include "node.h"
|
||||
|
||||
static int loopcount = 0; /* Count nested loops */
|
||||
int Roption;
|
||||
extern char options[];
|
||||
extern struct node *EmptyStatement;
|
||||
}
|
||||
|
||||
statement(register struct node **pnd;)
|
||||
{
|
||||
register struct node *nd;
|
||||
extern int return_occurred;
|
||||
} :
|
||||
/* We need some method for making sure lookahead is done, so ...
|
||||
*/
|
||||
[ PROGRAM
|
||||
/* LLlex never returns this */
|
||||
| %default
|
||||
{ if (options['R'] != Roption) {
|
||||
Roption = options['R'];
|
||||
nd = dot2leaf(Option);
|
||||
nd->nd_symb = 'R';
|
||||
nd->nd_INT = Roption;
|
||||
*pnd = nd =
|
||||
dot2node(Link, nd, NULLNODE);
|
||||
nd->nd_symb = ';';
|
||||
pnd = &(nd->nd_right);
|
||||
}
|
||||
}
|
||||
]
|
||||
[
|
||||
/*
|
||||
* This part is not in the reference grammar. The reference grammar
|
||||
* states : assignment | ProcedureCall | ...
|
||||
* but this gives LL(1) conflicts
|
||||
*/
|
||||
designator(pnd)
|
||||
[ { nd = dot2node(Call, *pnd, NULLNODE);
|
||||
nd->nd_symb = '(';
|
||||
}
|
||||
ActualParameters(&(nd->nd_right))?
|
||||
|
|
||||
[ BECOMES
|
||||
| '=' { error("':=' expected instead of '='");
|
||||
DOT = BECOMES;
|
||||
}
|
||||
]
|
||||
{ nd = dot2node(Stat, *pnd, NULLNODE); }
|
||||
expression(&(nd->nd_right))
|
||||
]
|
||||
{ *pnd = nd; }
|
||||
/*
|
||||
* end of changed part
|
||||
*/
|
||||
|
|
||||
IfStatement(pnd)
|
||||
|
|
||||
CaseStatement(pnd)
|
||||
|
|
||||
WHILE { *pnd = nd = dot2leaf(Stat); }
|
||||
expression(&(nd->nd_left))
|
||||
DO
|
||||
StatementSequence(&(nd->nd_right))
|
||||
END
|
||||
|
|
||||
REPEAT { *pnd = nd = dot2leaf(Stat); }
|
||||
StatementSequence(&(nd->nd_left))
|
||||
UNTIL
|
||||
expression(&(nd->nd_right))
|
||||
|
|
||||
{ loopcount++; }
|
||||
LOOP { *pnd = nd = dot2leaf(Stat); }
|
||||
StatementSequence(&((*pnd)->nd_right))
|
||||
END
|
||||
{ loopcount--; }
|
||||
|
|
||||
ForStatement(pnd)
|
||||
|
|
||||
WithStatement(pnd)
|
||||
|
|
||||
EXIT
|
||||
{ if (!loopcount) error("EXIT not in a LOOP");
|
||||
*pnd = dot2leaf(Stat);
|
||||
}
|
||||
|
|
||||
ReturnStatement(pnd)
|
||||
{ return_occurred = 1; }
|
||||
|
|
||||
/* empty */ { *pnd = EmptyStatement; }
|
||||
]
|
||||
;
|
||||
|
||||
/*
|
||||
* The next two rules in-line in "Statement", because of an LL(1) conflict
|
||||
|
||||
assignment:
|
||||
designator BECOMES expression
|
||||
;
|
||||
|
||||
ProcedureCall:
|
||||
designator ActualParameters?
|
||||
;
|
||||
*/
|
||||
|
||||
StatementSequence(register struct node **pnd;)
|
||||
{
|
||||
struct node *nd;
|
||||
register struct node *nd1;
|
||||
} :
|
||||
statement(pnd)
|
||||
[ %persistent
|
||||
';'
|
||||
statement(&nd)
|
||||
{ nd1 = dot2node(Link, *pnd, nd);
|
||||
*pnd = nd1;
|
||||
nd1->nd_symb = ';';
|
||||
pnd = &(nd1->nd_right);
|
||||
}
|
||||
]*
|
||||
;
|
||||
|
||||
IfStatement(struct node **pnd;)
|
||||
{
|
||||
register struct node *nd;
|
||||
} :
|
||||
IF { nd = dot2leaf(Stat);
|
||||
*pnd = nd;
|
||||
}
|
||||
expression(&(nd->nd_left))
|
||||
THEN { nd->nd_right = dot2leaf(Link);
|
||||
nd = nd->nd_right;
|
||||
}
|
||||
StatementSequence(&(nd->nd_left))
|
||||
[
|
||||
ELSIF { nd->nd_right = dot2leaf(Stat);
|
||||
nd = nd->nd_right;
|
||||
nd->nd_symb = IF;
|
||||
}
|
||||
expression(&(nd->nd_left))
|
||||
THEN { nd->nd_right = dot2leaf(Link);
|
||||
nd = nd->nd_right;
|
||||
}
|
||||
StatementSequence(&(nd->nd_left))
|
||||
]*
|
||||
[
|
||||
ELSE
|
||||
StatementSequence(&(nd->nd_right))
|
||||
]?
|
||||
END
|
||||
;
|
||||
|
||||
CaseStatement(struct node **pnd;)
|
||||
{
|
||||
register struct node *nd;
|
||||
struct type *tp = 0;
|
||||
} :
|
||||
CASE { *pnd = nd = dot2leaf(Stat); }
|
||||
expression(&(nd->nd_left))
|
||||
OF
|
||||
case(&(nd->nd_right), &tp)
|
||||
{ nd = nd->nd_right; }
|
||||
[
|
||||
'|'
|
||||
case(&(nd->nd_right), &tp)
|
||||
{ nd = nd->nd_right; }
|
||||
]*
|
||||
[ ELSE StatementSequence(&(nd->nd_right))
|
||||
]?
|
||||
END
|
||||
;
|
||||
|
||||
case(struct node **pnd; struct type **ptp;) :
|
||||
[ CaseLabelList(ptp, pnd)
|
||||
':' { *pnd = dot2node(Link, *pnd, NULLNODE); }
|
||||
StatementSequence(&((*pnd)->nd_right))
|
||||
]?
|
||||
{ *pnd = dot2node(Link, *pnd, NULLNODE);
|
||||
(*pnd)->nd_symb = '|';
|
||||
}
|
||||
;
|
||||
|
||||
/* inline in statement; lack of space
|
||||
WhileStatement(struct node **pnd;)
|
||||
{
|
||||
register struct node *nd;
|
||||
}:
|
||||
WHILE { *pnd = nd = dot2leaf(Stat); }
|
||||
expression(&(nd->nd_left))
|
||||
DO
|
||||
StatementSequence(&(nd->nd_right))
|
||||
END
|
||||
;
|
||||
|
||||
RepeatStatement(struct node **pnd;)
|
||||
{
|
||||
register struct node *nd;
|
||||
}:
|
||||
REPEAT { *pnd = nd = dot2leaf(Stat); }
|
||||
StatementSequence(&(nd->nd_left))
|
||||
UNTIL
|
||||
expression(&(nd->nd_right))
|
||||
;
|
||||
*/
|
||||
|
||||
ForStatement(struct node **pnd;)
|
||||
{
|
||||
register struct node *nd, *nd1;
|
||||
struct node *dummy;
|
||||
}:
|
||||
FOR { *pnd = nd = dot2leaf(Stat); }
|
||||
IDENT { nd->nd_IDF = dot.TOK_IDF; }
|
||||
BECOMES { nd->nd_left = nd1 = dot2leaf(Stat); }
|
||||
expression(&(nd1->nd_left))
|
||||
TO
|
||||
expression(&(nd1->nd_right))
|
||||
[
|
||||
BY
|
||||
ConstExpression(&dummy)
|
||||
{ if (!(dummy->nd_type->tp_fund & T_INTORCARD)) {
|
||||
error("illegal type in BY clause");
|
||||
}
|
||||
nd1->nd_INT = dummy->nd_INT;
|
||||
FreeNode(dummy);
|
||||
}
|
||||
|
|
||||
{ nd1->nd_INT = 1; }
|
||||
]
|
||||
DO
|
||||
StatementSequence(&(nd->nd_right))
|
||||
END
|
||||
;
|
||||
|
||||
/* inline in Statement; lack of space
|
||||
LoopStatement(struct node **pnd;):
|
||||
LOOP { *pnd = dot2leaf(Stat); }
|
||||
StatementSequence(&((*pnd)->nd_right))
|
||||
END
|
||||
;
|
||||
*/
|
||||
|
||||
WithStatement(struct node **pnd;)
|
||||
{
|
||||
register struct node *nd;
|
||||
}:
|
||||
WITH { *pnd = nd = dot2leaf(Stat); }
|
||||
designator(&(nd->nd_left))
|
||||
DO
|
||||
StatementSequence(&(nd->nd_right))
|
||||
END
|
||||
;
|
||||
|
||||
ReturnStatement(struct node **pnd;)
|
||||
{
|
||||
register struct def *df = CurrentScope->sc_definedby;
|
||||
register struct node *nd;
|
||||
} :
|
||||
|
||||
RETURN { *pnd = nd = dot2leaf(Stat); }
|
||||
[
|
||||
expression(&(nd->nd_right))
|
||||
{ if (scopeclosed(CurrentScope)) {
|
||||
error("a module body has no result value");
|
||||
}
|
||||
else if (! ResultType(df->df_type)) {
|
||||
error("procedure \"%s\" has no result value", df->df_idf->id_text);
|
||||
}
|
||||
}
|
||||
|
|
||||
{ if (ResultType(df->df_type)) {
|
||||
error("procedure \"%s\" must return a value", df->df_idf->id_text);
|
||||
}
|
||||
}
|
||||
]
|
||||
;
|
||||
295
lang/m2/comp/tab.c
Normal file
295
lang/m2/comp/tab.c
Normal file
@@ -0,0 +1,295 @@
|
||||
/* @cc tab.c -o $INSTALLDIR/tab@
|
||||
tab - table generator
|
||||
|
||||
Author: Erik Baalbergen (..tjalk!erikb)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static char *RcsId = "$Header$";
|
||||
|
||||
#define MAXTAB 10000
|
||||
#define MAXBUF 10000
|
||||
#define COMCOM '-'
|
||||
#define FILECOM '%'
|
||||
|
||||
int InputForm = 'c';
|
||||
char OutputForm[MAXBUF] = "%s,\n";
|
||||
int TabSize = 257;
|
||||
char *Table[MAXTAB];
|
||||
char *Name;
|
||||
char *ProgCall;
|
||||
|
||||
main(argc, argv)
|
||||
char *argv[];
|
||||
{
|
||||
ProgCall = *argv++;
|
||||
argc--;
|
||||
while (argc-- > 0) {
|
||||
if (**argv == COMCOM) {
|
||||
option(*argv++);
|
||||
}
|
||||
else {
|
||||
process(*argv++, InputForm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
Salloc(s)
|
||||
char *s;
|
||||
{
|
||||
char *malloc();
|
||||
char *ns = malloc(strlen(s) + 1);
|
||||
|
||||
if (ns) {
|
||||
strcpy(ns, s);
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
|
||||
option(str)
|
||||
char *str;
|
||||
{
|
||||
/* note that *str indicates the source of the option:
|
||||
either COMCOM (from command line) or FILECOM (from a file).
|
||||
*/
|
||||
switch (*++str) {
|
||||
|
||||
case ' ': /* command */
|
||||
case '\t':
|
||||
case '\0':
|
||||
break;
|
||||
case 'I':
|
||||
InputForm = *++str;
|
||||
break;
|
||||
case 'f':
|
||||
if (*++str == '\0') {
|
||||
fprintf(stderr, "%s: -f: name expected\n", ProgCall);
|
||||
exit(1);
|
||||
}
|
||||
DoFile(str);
|
||||
break;
|
||||
case 'F':
|
||||
sprintf(OutputForm, "%s\n", ++str);
|
||||
break;
|
||||
case 'T':
|
||||
printf("%s\n", ++str);
|
||||
break;
|
||||
case 'p':
|
||||
PrintTable();
|
||||
break;
|
||||
case 'C':
|
||||
ClearTable();
|
||||
break;
|
||||
case 'S':
|
||||
{
|
||||
register i = stoi(++str);
|
||||
|
||||
if (i <= 0 || i > MAXTAB) {
|
||||
fprintf(stderr, "%s: size would exceed maximum\n",
|
||||
ProgCall);
|
||||
}
|
||||
else {
|
||||
TabSize = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "%s: bad option -%s\n", ProgCall, str);
|
||||
}
|
||||
}
|
||||
|
||||
ClearTable()
|
||||
{
|
||||
register i;
|
||||
|
||||
for (i = 0; i < MAXTAB; i++) {
|
||||
Table[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PrintTable()
|
||||
{
|
||||
register i;
|
||||
|
||||
for (i = 0; i < TabSize; i++) {
|
||||
if (Table[i]) {
|
||||
printf(OutputForm, Table[i]);
|
||||
}
|
||||
else {
|
||||
printf(OutputForm, "0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process(str, format)
|
||||
char *str;
|
||||
{
|
||||
char *cstr = str;
|
||||
char *Name = cstr; /* overwrite original string! */
|
||||
|
||||
/* strip of the entry name
|
||||
*/
|
||||
while (*str && *str != ':') {
|
||||
if (*str == '\\') {
|
||||
++str;
|
||||
}
|
||||
*cstr++ = *str++;
|
||||
}
|
||||
|
||||
if (*str != ':') {
|
||||
fprintf(stderr, "%s: bad specification: \"%s\", ignored\n",
|
||||
ProgCall, Name);
|
||||
return 0;
|
||||
}
|
||||
*cstr = '\0';
|
||||
str++;
|
||||
|
||||
switch (format) {
|
||||
|
||||
case 'c':
|
||||
return c_proc(str, Name);
|
||||
default:
|
||||
fprintf(stderr, "%s: bad input format\n", ProgCall);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
c_proc(str, Name)
|
||||
char *str;
|
||||
char *Name;
|
||||
{
|
||||
int ch, ch2;
|
||||
int quoted();
|
||||
|
||||
while (*str) {
|
||||
if (*str == '\\') {
|
||||
ch = quoted(&str);
|
||||
}
|
||||
else {
|
||||
ch = *str++;
|
||||
}
|
||||
if (*str == '-') {
|
||||
if (*++str == '\\') {
|
||||
ch2 = quoted(&str);
|
||||
}
|
||||
else {
|
||||
if (ch2 = *str++);
|
||||
else str--;
|
||||
}
|
||||
if (ch > ch2) {
|
||||
fprintf(stderr, "%s: bad range\n", ProgCall);
|
||||
return 0;
|
||||
}
|
||||
if (ch >= 0 && ch2 <= 255)
|
||||
while (ch <= ch2)
|
||||
Table[ch++] = Salloc(Name);
|
||||
}
|
||||
else {
|
||||
if (ch >= 0 && ch <= 255)
|
||||
Table[ch] = Salloc(Name);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
quoted(pstr)
|
||||
char **pstr;
|
||||
{
|
||||
register int ch;
|
||||
register int i;
|
||||
register char *str = *pstr;
|
||||
|
||||
if ((*++str >= '0') && (*str <= '9')) {
|
||||
ch = 0;
|
||||
for (i = 0; i < 3; i++) {
|
||||
ch = 8 * ch + *str - '0';
|
||||
if (*++str < '0' || *str > '9')
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (*str++) {
|
||||
|
||||
case 'n':
|
||||
ch = '\n';
|
||||
break;
|
||||
case 't':
|
||||
ch = '\t';
|
||||
break;
|
||||
case 'b':
|
||||
ch = '\b';
|
||||
break;
|
||||
case 'r':
|
||||
ch = '\r';
|
||||
break;
|
||||
case 'f':
|
||||
ch = '\f';
|
||||
break;
|
||||
default :
|
||||
ch = *str;
|
||||
}
|
||||
}
|
||||
*pstr = str;
|
||||
return ch & 0377;
|
||||
}
|
||||
|
||||
int
|
||||
stoi(str)
|
||||
char *str;
|
||||
{
|
||||
register i = 0;
|
||||
|
||||
while (*str >= '0' && *str <= '9') {
|
||||
i = i * 10 + *str++ - '0';
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
char *
|
||||
getline(s, n, fp)
|
||||
char *s;
|
||||
FILE *fp;
|
||||
{
|
||||
register c = getc(fp);
|
||||
char *str = s;
|
||||
|
||||
while (n--) {
|
||||
if (c == EOF) {
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
if (c == '\n') {
|
||||
*str++ = '\0';
|
||||
return s;
|
||||
}
|
||||
*str++ = c;
|
||||
c = getc(fp);
|
||||
}
|
||||
s[n - 1] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
#define BUFSIZE 1024
|
||||
|
||||
DoFile(name)
|
||||
char *name;
|
||||
{
|
||||
char text[BUFSIZE];
|
||||
FILE *fp;
|
||||
|
||||
if ((fp = fopen(name, "r")) == NULL) {
|
||||
fprintf(stderr, "%s: cannot read file %s\n", ProgCall, name);
|
||||
exit(1);
|
||||
}
|
||||
while (getline(text, BUFSIZE, fp) != NULL) {
|
||||
if (text[0] == FILECOM) {
|
||||
option(text);
|
||||
}
|
||||
else {
|
||||
process(text, InputForm);
|
||||
}
|
||||
}
|
||||
}
|
||||
137
lang/m2/comp/tmpvar.C
Normal file
137
lang/m2/comp/tmpvar.C
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* T E M P O R A R Y V A R I A B L E S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* Code for the allocation and de-allocation of temporary variables,
|
||||
allowing re-use.
|
||||
The routines use "ProcScope" instead of "CurrentScope", because
|
||||
"CurrentScope" also reflects WITH statements, and these scopes do not
|
||||
have local variabes.
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <em_reg.h>
|
||||
#include <alloc.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "LLlex.h"
|
||||
#include "def.h"
|
||||
#include "type.h"
|
||||
#include "scope.h"
|
||||
#include "main.h"
|
||||
|
||||
struct tmpvar {
|
||||
struct tmpvar *t_next;
|
||||
arith t_offset; /* offset from LocalBase */
|
||||
};
|
||||
|
||||
/* STATICALLOCDEF "tmpvar" 10 */
|
||||
|
||||
static struct tmpvar *TmpInts, /* for integer temporaries */
|
||||
*TmpPtrs; /* for pointer temporaries */
|
||||
static struct scope *ProcScope; /* scope of procedure in which the
|
||||
temporaries are allocated
|
||||
*/
|
||||
|
||||
TmpOpen(sc) struct scope *sc;
|
||||
{
|
||||
/* Initialize for temporaries in scope "sc".
|
||||
*/
|
||||
ProcScope = sc;
|
||||
}
|
||||
|
||||
arith
|
||||
TmpSpace(sz, al)
|
||||
arith sz;
|
||||
{
|
||||
register struct scope *sc = ProcScope;
|
||||
|
||||
sc->sc_off = - WA(align(sz - sc->sc_off, al));
|
||||
return sc->sc_off;
|
||||
}
|
||||
|
||||
STATIC arith
|
||||
NewTmp(plist, sz, al, regtype)
|
||||
struct tmpvar **plist;
|
||||
arith sz;
|
||||
{
|
||||
register arith offset;
|
||||
register struct tmpvar *tmp;
|
||||
|
||||
if (!*plist) {
|
||||
offset = TmpSpace(sz, al);
|
||||
if (! options['n']) C_ms_reg(offset, sz, regtype, 0);
|
||||
}
|
||||
else {
|
||||
tmp = *plist;
|
||||
offset = tmp->t_offset;
|
||||
*plist = tmp->t_next;
|
||||
free_tmpvar(tmp);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
arith
|
||||
NewInt()
|
||||
{
|
||||
return NewTmp(&TmpInts, int_size, int_align, reg_any);
|
||||
}
|
||||
|
||||
arith
|
||||
NewPtr()
|
||||
{
|
||||
return NewTmp(&TmpPtrs, pointer_size, pointer_align, reg_pointer);
|
||||
}
|
||||
|
||||
STATIC
|
||||
FreeTmp(plist, off)
|
||||
struct tmpvar **plist;
|
||||
arith off;
|
||||
{
|
||||
register struct tmpvar *tmp = new_tmpvar();
|
||||
|
||||
tmp->t_next = *plist;
|
||||
tmp->t_offset = off;
|
||||
*plist = tmp;
|
||||
}
|
||||
|
||||
FreeInt(off)
|
||||
arith off;
|
||||
{
|
||||
FreeTmp(&TmpInts, off);
|
||||
}
|
||||
|
||||
FreePtr(off)
|
||||
arith off;
|
||||
{
|
||||
FreeTmp(&TmpPtrs, off);
|
||||
}
|
||||
|
||||
TmpClose()
|
||||
{
|
||||
register struct tmpvar *tmp, *tmp1;
|
||||
|
||||
tmp = TmpInts;
|
||||
while (tmp) {
|
||||
tmp1 = tmp;
|
||||
tmp = tmp->t_next;
|
||||
free_tmpvar(tmp1);
|
||||
}
|
||||
tmp = TmpPtrs;
|
||||
while (tmp) {
|
||||
tmp1 = tmp;
|
||||
tmp = tmp->t_next;
|
||||
free_tmpvar(tmp1);
|
||||
}
|
||||
TmpInts = TmpPtrs = 0;
|
||||
}
|
||||
113
lang/m2/comp/tokenname.c
Normal file
113
lang/m2/comp/tokenname.c
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* T O K E N D E F I N I T I O N S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "tokenname.h"
|
||||
#include "Lpars.h"
|
||||
#include "idf.h"
|
||||
|
||||
/* To centralize the declaration of %tokens, their presence in this
|
||||
file is taken as their declaration. The Makefile will produce
|
||||
a grammar file (tokenfile.g) from this file. This scheme ensures
|
||||
that all tokens have a printable name.
|
||||
Also, the "token2str.c" file is produced from this file.
|
||||
*/
|
||||
|
||||
#ifdef ___XXX___
|
||||
struct tokenname tkspec[] = { /* the names of the special tokens */
|
||||
{IDENT, "identifier"},
|
||||
{STRING, "string"},
|
||||
{INTEGER, "number"},
|
||||
{REAL, "real"},
|
||||
{0, ""}
|
||||
};
|
||||
|
||||
struct tokenname tkcomp[] = { /* names of the composite tokens */
|
||||
{LESSEQUAL, "<="},
|
||||
{GREATEREQUAL, ">="},
|
||||
{UPTO, ".."},
|
||||
{BECOMES, ":="},
|
||||
{0, ""}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct tokenname tkidf[] = { /* names of the identifier tokens */
|
||||
{AND, "AND"},
|
||||
{ARRAY, "ARRAY"},
|
||||
{BEGIN, "BEGIN"},
|
||||
{BY, "BY"},
|
||||
{CASE, "CASE"},
|
||||
{CONST, "CONST"},
|
||||
{DEFINITION, "DEFINITION"},
|
||||
{DIV, "DIV"},
|
||||
{DO, "DO"},
|
||||
{ELSE, "ELSE"},
|
||||
{ELSIF, "ELSIF"},
|
||||
{END, "END"},
|
||||
{EXIT, "EXIT"},
|
||||
{EXPORT, "EXPORT"},
|
||||
{FOR, "FOR"},
|
||||
{FROM, "FROM"},
|
||||
{IF, "IF"},
|
||||
{IMPLEMENTATION, "IMPLEMENTATION"},
|
||||
{IMPORT, "IMPORT"},
|
||||
{IN, "IN"},
|
||||
{LOOP, "LOOP"},
|
||||
{MOD, "MOD"},
|
||||
{MODULE, "MODULE"},
|
||||
{NOT, "NOT"},
|
||||
{OF, "OF"},
|
||||
{OR, "OR"},
|
||||
{POINTER, "POINTER"},
|
||||
{PROCEDURE, "PROCEDURE"},
|
||||
{QUALIFIED, "QUALIFIED"},
|
||||
{RECORD, "RECORD"},
|
||||
{REPEAT, "REPEAT"},
|
||||
{RETURN, "RETURN"},
|
||||
{SET, "SET"},
|
||||
{THEN, "THEN"},
|
||||
{TO, "TO"},
|
||||
{TYPE, "TYPE"},
|
||||
{UNTIL, "UNTIL"},
|
||||
{VAR, "VAR"},
|
||||
{WHILE, "WHILE"},
|
||||
{WITH, "WITH"},
|
||||
{0, ""}
|
||||
};
|
||||
|
||||
#ifdef ___XXX___
|
||||
struct tokenname tkinternal[] = { /* internal keywords */
|
||||
{PROGRAM, ""},
|
||||
{COERCION, ""},
|
||||
{0, "0"}
|
||||
};
|
||||
|
||||
struct tokenname tkstandard[] = { /* standard identifiers */
|
||||
{0, ""}
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Some routines to handle tokennames */
|
||||
|
||||
reserve(resv)
|
||||
register struct tokenname *resv;
|
||||
{
|
||||
/* The names of the tokens described in resv are entered
|
||||
as reserved words.
|
||||
*/
|
||||
register struct idf *p;
|
||||
|
||||
while (resv->tn_symbol) {
|
||||
p = str2idf(resv->tn_name, 0);
|
||||
if (!p) fatal("out of Memory");
|
||||
p->id_reserved = resv->tn_symbol;
|
||||
resv++;
|
||||
}
|
||||
}
|
||||
17
lang/m2/comp/tokenname.h
Normal file
17
lang/m2/comp/tokenname.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* T O K E N N A M E S T R U C T U R E */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
struct tokenname { /* Used for defining the name of a
|
||||
token as identified by its symbol
|
||||
*/
|
||||
int tn_symbol;
|
||||
char *tn_name;
|
||||
};
|
||||
185
lang/m2/comp/type.H
Normal file
185
lang/m2/comp/type.H
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* T Y P E D E S C R I P T O R S T R U C T U R E */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
struct paramlist { /* structure for parameterlist of a PROCEDURE */
|
||||
struct paramlist *par_next;
|
||||
struct def *par_def; /* "df" of parameter */
|
||||
#define IsVarParam(xpar) ((int) ((xpar)->par_def->df_flags & D_VARPAR))
|
||||
#define TypeOfParam(xpar) ((xpar)->par_def->df_type)
|
||||
};
|
||||
|
||||
/* ALLOCDEF "paramlist" 20 */
|
||||
|
||||
struct enume {
|
||||
struct def *en_enums; /* Definitions of enumeration literals */
|
||||
arith en_ncst; /* Number of constants */
|
||||
label en_rck; /* Label of range check descriptor */
|
||||
#define enm_enums tp_value.tp_enum->en_enums
|
||||
#define enm_ncst tp_value.tp_enum->en_ncst
|
||||
#define enm_rck tp_value.tp_enum->en_rck
|
||||
};
|
||||
|
||||
/* ALLOCDEF "enume" 5 */
|
||||
|
||||
struct subrange {
|
||||
arith su_lb, su_ub; /* lower bound and upper bound */
|
||||
label su_rck; /* label of range check descriptor */
|
||||
#define sub_lb tp_value.tp_subrange->su_lb
|
||||
#define sub_ub tp_value.tp_subrange->su_ub
|
||||
#define sub_rck tp_value.tp_subrange->su_rck
|
||||
};
|
||||
|
||||
/* ALLOCDEF "subrange" 5 */
|
||||
|
||||
struct array {
|
||||
struct type *ar_elem; /* type of elements */
|
||||
label ar_descr; /* label of array descriptor */
|
||||
arith ar_elsize; /* size of elements */
|
||||
#define arr_elem tp_value.tp_arr->ar_elem
|
||||
#define arr_descr tp_value.tp_arr->ar_descr
|
||||
#define arr_elsize tp_value.tp_arr->ar_elsize
|
||||
};
|
||||
|
||||
/* ALLOCDEF "array" 5 */
|
||||
|
||||
struct record {
|
||||
struct scope *rc_scope; /* scope of this record */
|
||||
/* members are in the symbol table */
|
||||
#define rec_scope tp_value.tp_record.rc_scope
|
||||
};
|
||||
|
||||
struct proc {
|
||||
struct paramlist *pr_params;
|
||||
arith pr_nbpar;
|
||||
#define prc_params tp_value.tp_proc.pr_params
|
||||
#define prc_nbpar tp_value.tp_proc.pr_nbpar
|
||||
};
|
||||
|
||||
struct type {
|
||||
struct type *tp_next; /* used with ARRAY, PROCEDURE, POINTER, SET,
|
||||
SUBRANGE, EQUAL
|
||||
*/
|
||||
int tp_fund; /* fundamental type or constructor */
|
||||
#define T_RECORD 0x0001
|
||||
#define T_ENUMERATION 0x0002
|
||||
#define T_INTEGER 0x0004
|
||||
#define T_CARDINAL 0x0008
|
||||
#define T_EQUAL 0x0010
|
||||
#define T_REAL 0x0020
|
||||
#define T_HIDDEN 0x0040
|
||||
#define T_POINTER 0x0080
|
||||
#define T_CHAR 0x0100
|
||||
#define T_WORD 0x0200
|
||||
#define T_SET 0x0400
|
||||
#define T_SUBRANGE 0x0800
|
||||
#define T_PROCEDURE 0x1000
|
||||
#define T_ARRAY 0x2000
|
||||
#define T_STRING 0x4000
|
||||
#define T_INTORCARD (T_INTEGER|T_CARDINAL)
|
||||
#define T_NUMERIC (T_INTORCARD|T_REAL)
|
||||
#define T_INDEX (T_ENUMERATION|T_CHAR|T_SUBRANGE)
|
||||
#define T_DISCRETE (T_INDEX|T_INTORCARD)
|
||||
#define T_CONSTRUCTED (T_ARRAY|T_SET|T_RECORD)
|
||||
int tp_align; /* alignment requirement of this type */
|
||||
arith tp_size; /* size of this type */
|
||||
union {
|
||||
struct enume *tp_enum;
|
||||
struct subrange *tp_subrange;
|
||||
struct array *tp_arr;
|
||||
struct record tp_record;
|
||||
struct proc tp_proc;
|
||||
} tp_value;
|
||||
};
|
||||
|
||||
/* ALLOCDEF "type" 50 */
|
||||
|
||||
extern struct type
|
||||
*bool_type,
|
||||
*char_type,
|
||||
*int_type,
|
||||
*card_type,
|
||||
*longint_type,
|
||||
*real_type,
|
||||
*longreal_type,
|
||||
*word_type,
|
||||
*byte_type,
|
||||
*address_type,
|
||||
*intorcard_type,
|
||||
*bitset_type,
|
||||
*std_type,
|
||||
*error_type; /* All from type.c */
|
||||
|
||||
extern int
|
||||
word_align,
|
||||
short_align,
|
||||
int_align,
|
||||
long_align,
|
||||
float_align,
|
||||
double_align,
|
||||
pointer_align,
|
||||
struct_align; /* All from type.c */
|
||||
|
||||
extern arith
|
||||
word_size,
|
||||
dword_size,
|
||||
short_size,
|
||||
int_size,
|
||||
long_size,
|
||||
float_size,
|
||||
double_size,
|
||||
pointer_size; /* All from type.c */
|
||||
|
||||
extern arith
|
||||
align(); /* type.c */
|
||||
|
||||
struct type
|
||||
*construct_type(),
|
||||
*standard_type(),
|
||||
*set_type(),
|
||||
*subr_type(),
|
||||
*proc_type(),
|
||||
*enum_type(),
|
||||
*qualified_type(),
|
||||
*RemoveEqual(); /* All from type.c */
|
||||
|
||||
#define NULLTYPE ((struct type *) 0)
|
||||
|
||||
#define IsConformantArray(tpx) ((tpx)->tp_fund==T_ARRAY && (tpx)->tp_size==0)
|
||||
#define bounded(tpx) ((tpx)->tp_fund & T_INDEX)
|
||||
#define complex(tpx) ((tpx)->tp_fund & (T_RECORD|T_ARRAY))
|
||||
#define WA(sz) (align(sz, (int) word_size))
|
||||
#ifdef DEBUG
|
||||
#define ResultType(tpx) (assert((tpx)->tp_fund == T_PROCEDURE),\
|
||||
(tpx)->tp_next)
|
||||
#define ParamList(tpx) (assert((tpx)->tp_fund == T_PROCEDURE),\
|
||||
(tpx)->prc_params)
|
||||
#define IndexType(tpx) (assert((tpx)->tp_fund == T_ARRAY),\
|
||||
(tpx)->tp_next)
|
||||
#define ElementType(tpx) (assert((tpx)->tp_fund == T_SET),\
|
||||
(tpx)->tp_next)
|
||||
#define PointedtoType(tpx) (assert((tpx)->tp_fund == T_POINTER),\
|
||||
(tpx)->tp_next)
|
||||
#else DEBUG
|
||||
#define ResultType(tpx) ((tpx)->tp_next)
|
||||
#define ParamList(tpx) ((tpx)->prc_params)
|
||||
#define IndexType(tpx) ((tpx)->tp_next)
|
||||
#define ElementType(tpx) ((tpx)->tp_next)
|
||||
#define PointedtoType(tpx) ((tpx)->tp_next)
|
||||
#endif DEBUG
|
||||
#define BaseType(tpx) ((tpx)->tp_fund == T_SUBRANGE ? (tpx)->tp_next : \
|
||||
(tpx))
|
||||
#define IsConstructed(tpx) ((tpx)->tp_fund & T_CONSTRUCTED)
|
||||
|
||||
extern long full_mask[];
|
||||
extern long int_mask[];
|
||||
|
||||
#define fit(n, i) (((n) + ((arith)0x80<<(((i)-1)*8)) & ~full_mask[(i)]) == 0)
|
||||
#define ufit(n, i) (((n) & ~full_mask[(i)]) == 0)
|
||||
755
lang/m2/comp/type.c
Normal file
755
lang/m2/comp/type.c
Normal file
@@ -0,0 +1,755 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* T Y P E D E F I N I T I O N M E C H A N I S M */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "target_sizes.h"
|
||||
#include "debug.h"
|
||||
#include "maxset.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <alloc.h>
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <em_code.h>
|
||||
|
||||
#include "LLlex.h"
|
||||
#include "def.h"
|
||||
#include "type.h"
|
||||
#include "idf.h"
|
||||
#include "node.h"
|
||||
#include "const.h"
|
||||
#include "scope.h"
|
||||
#include "walk.h"
|
||||
#include "chk_expr.h"
|
||||
|
||||
int
|
||||
word_align = AL_WORD,
|
||||
short_align = AL_SHORT,
|
||||
int_align = AL_INT,
|
||||
long_align = AL_LONG,
|
||||
float_align = AL_FLOAT,
|
||||
double_align = AL_DOUBLE,
|
||||
pointer_align = AL_POINTER,
|
||||
struct_align = AL_STRUCT;
|
||||
|
||||
int
|
||||
maxset = MAXSET;
|
||||
|
||||
arith
|
||||
word_size = SZ_WORD,
|
||||
dword_size = 2 * SZ_WORD,
|
||||
int_size = SZ_INT,
|
||||
short_size = SZ_SHORT,
|
||||
long_size = SZ_LONG,
|
||||
float_size = SZ_FLOAT,
|
||||
double_size = SZ_DOUBLE,
|
||||
pointer_size = SZ_POINTER;
|
||||
|
||||
struct type
|
||||
*bool_type,
|
||||
*char_type,
|
||||
*int_type,
|
||||
*card_type,
|
||||
*longint_type,
|
||||
*real_type,
|
||||
*longreal_type,
|
||||
*word_type,
|
||||
*byte_type,
|
||||
*address_type,
|
||||
*intorcard_type,
|
||||
*bitset_type,
|
||||
*std_type,
|
||||
*error_type;
|
||||
|
||||
struct type *
|
||||
construct_type(fund, tp)
|
||||
int fund;
|
||||
register struct type *tp;
|
||||
{
|
||||
/* fund must be a type constructor.
|
||||
The pointer to the constructed type is returned.
|
||||
*/
|
||||
register struct type *dtp = new_type();
|
||||
|
||||
switch (dtp->tp_fund = fund) {
|
||||
case T_PROCEDURE:
|
||||
case T_POINTER:
|
||||
case T_HIDDEN:
|
||||
dtp->tp_align = pointer_align;
|
||||
dtp->tp_size = pointer_size;
|
||||
break;
|
||||
|
||||
case T_SET:
|
||||
dtp->tp_align = word_align;
|
||||
break;
|
||||
|
||||
case T_ARRAY:
|
||||
dtp->tp_value.tp_arr = new_array();
|
||||
if (tp) dtp->tp_align = tp->tp_align;
|
||||
break;
|
||||
|
||||
case T_SUBRANGE:
|
||||
assert(tp != 0);
|
||||
dtp->tp_value.tp_subrange = new_subrange();
|
||||
dtp->tp_align = tp->tp_align;
|
||||
dtp->tp_size = tp->tp_size;
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("funny type constructor");
|
||||
}
|
||||
|
||||
dtp->tp_next = tp;
|
||||
return dtp;
|
||||
}
|
||||
|
||||
arith
|
||||
align(pos, al)
|
||||
arith pos;
|
||||
int al;
|
||||
{
|
||||
int i = pos % al;
|
||||
|
||||
if (i) return pos + (al - i);
|
||||
return pos;
|
||||
}
|
||||
|
||||
struct type *
|
||||
standard_type(fund, align, size)
|
||||
int fund;
|
||||
int align;
|
||||
arith size;
|
||||
{
|
||||
register struct type *tp = new_type();
|
||||
|
||||
tp->tp_fund = fund;
|
||||
tp->tp_align = align;
|
||||
tp->tp_size = size;
|
||||
if (fund == T_ENUMERATION || fund == T_CHAR) {
|
||||
tp->tp_value.tp_enum = new_enume();
|
||||
}
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
InitTypes()
|
||||
{
|
||||
/* Initialize the predefined types
|
||||
*/
|
||||
register struct type *tp;
|
||||
|
||||
/* first, do some checking
|
||||
*/
|
||||
if ((int) int_size != (int) word_size) {
|
||||
fatal("integer size not equal to word size");
|
||||
}
|
||||
|
||||
if ((int) int_size != (int) pointer_size) {
|
||||
fatal("cardinal size not equal to pointer size");
|
||||
}
|
||||
|
||||
if ((int) long_size < (int) int_size ||
|
||||
(int) long_size % (int) word_size != 0) {
|
||||
fatal("illegal long integer size");
|
||||
}
|
||||
|
||||
if ((int) double_size < (int) float_size) {
|
||||
fatal("long real size smaller than real size");
|
||||
}
|
||||
|
||||
/* character type
|
||||
*/
|
||||
char_type = standard_type(T_CHAR, 1, (arith) 1);
|
||||
char_type->enm_ncst = 256;
|
||||
|
||||
/* boolean type
|
||||
*/
|
||||
bool_type = standard_type(T_ENUMERATION, 1, (arith) 1);
|
||||
bool_type->enm_ncst = 2;
|
||||
|
||||
/* integer types, also a "intorcard", for integer constants between
|
||||
0 and MAX(INTEGER)
|
||||
*/
|
||||
int_type = standard_type(T_INTEGER, int_align, int_size);
|
||||
longint_type = standard_type(T_INTEGER, long_align, long_size);
|
||||
card_type = standard_type(T_CARDINAL, int_align, int_size);
|
||||
intorcard_type = standard_type(T_INTORCARD, int_align, int_size);
|
||||
|
||||
/* floating types
|
||||
*/
|
||||
real_type = standard_type(T_REAL, float_align, float_size);
|
||||
longreal_type = standard_type(T_REAL, double_align, double_size);
|
||||
|
||||
/* SYSTEM types
|
||||
*/
|
||||
word_type = standard_type(T_WORD, word_align, word_size);
|
||||
byte_type = standard_type(T_WORD, 1, (arith) 1);
|
||||
address_type = construct_type(T_POINTER, word_type);
|
||||
|
||||
/* create BITSET type
|
||||
TYPE BITSET = SET OF [0..W-1];
|
||||
The subrange is a subrange of type cardinal, because the lower bound
|
||||
is a non-negative integer (See Rep. 6.3)
|
||||
*/
|
||||
tp = construct_type(T_SUBRANGE, card_type);
|
||||
tp->sub_lb = 0;
|
||||
tp->sub_ub = (int) word_size * 8 - 1;
|
||||
bitset_type = set_type(tp);
|
||||
|
||||
/* a unique type for standard procedures and functions
|
||||
*/
|
||||
std_type = construct_type(T_PROCEDURE, NULLTYPE);
|
||||
|
||||
/* a unique type indicating an error
|
||||
*/
|
||||
error_type = new_type();
|
||||
*error_type = *char_type;
|
||||
}
|
||||
|
||||
STATIC
|
||||
u_small(tp, n)
|
||||
register struct type *tp;
|
||||
arith n;
|
||||
{
|
||||
if (ufit(n, 1)) {
|
||||
tp->tp_size = 1;
|
||||
tp->tp_align = 1;
|
||||
}
|
||||
else if (ufit(n, (int)short_size)) {
|
||||
tp->tp_size = short_size;
|
||||
tp->tp_align = short_align;
|
||||
}
|
||||
}
|
||||
|
||||
struct type *
|
||||
enum_type(EnumList)
|
||||
struct node *EnumList;
|
||||
{
|
||||
register struct type *tp =
|
||||
standard_type(T_ENUMERATION, int_align, int_size);
|
||||
|
||||
EnterEnumList(EnumList, tp);
|
||||
if (! fit(tp->enm_ncst, (int) int_size)) {
|
||||
node_error(EnumList, "too many enumeration literals");
|
||||
}
|
||||
u_small(tp, (arith) (tp->enm_ncst-1));
|
||||
return tp;
|
||||
}
|
||||
|
||||
struct type *
|
||||
qualified_type(nd)
|
||||
register struct node *nd;
|
||||
{
|
||||
register struct def *df;
|
||||
|
||||
if (ChkDesignator(nd)) {
|
||||
if (nd->nd_class != Def) {
|
||||
node_error(nd, "type expected");
|
||||
FreeNode(nd);
|
||||
return error_type;
|
||||
}
|
||||
|
||||
df = nd->nd_def;
|
||||
if (df->df_kind&(D_ISTYPE|D_FORWARD|D_FORWTYPE|D_ERROR)) {
|
||||
if (! df->df_type) {
|
||||
node_error(nd,"type \"%s\" not (yet) declared", df->df_idf->id_text);
|
||||
FreeNode(nd);
|
||||
return error_type;
|
||||
}
|
||||
FreeNode(nd);
|
||||
if (df->df_kind == D_FORWTYPE) {
|
||||
df->df_kind = D_FTYPE;
|
||||
}
|
||||
return df->df_type;
|
||||
}
|
||||
node_error(nd,"identifier \"%s\" is not a type", df->df_idf->id_text);
|
||||
}
|
||||
FreeNode(nd);
|
||||
return error_type;
|
||||
}
|
||||
|
||||
chk_basesubrange(tp, base)
|
||||
register struct type *tp, *base;
|
||||
{
|
||||
/* A subrange had a specified base. Check that the bases conform.
|
||||
*/
|
||||
|
||||
assert(tp->tp_fund == T_SUBRANGE);
|
||||
|
||||
if (base->tp_fund == T_SUBRANGE) {
|
||||
/* Check that the bounds of "tp" fall within the range
|
||||
of "base".
|
||||
*/
|
||||
int fund = base->tp_next->tp_fund;
|
||||
|
||||
if (! chk_bounds(base->sub_lb, tp->sub_lb, fund) ||
|
||||
! chk_bounds(base->sub_ub, tp->sub_ub, fund)) {
|
||||
error("base type has insufficient range");
|
||||
}
|
||||
base = base->tp_next;
|
||||
}
|
||||
|
||||
if (base->tp_fund & (T_ENUMERATION|T_CHAR)) {
|
||||
if (tp->tp_next != base) {
|
||||
error("specified base does not conform");
|
||||
}
|
||||
}
|
||||
else if (base != card_type && base != int_type) {
|
||||
error("illegal base for a subrange");
|
||||
}
|
||||
else if (base == int_type && tp->tp_next == card_type &&
|
||||
(tp->sub_ub > max_int || tp->sub_ub < 0)) {
|
||||
error("upperbound to large for type INTEGER");
|
||||
}
|
||||
else if (base != tp->tp_next && base != int_type) {
|
||||
error("specified base does not conform");
|
||||
}
|
||||
|
||||
tp->tp_next = base;
|
||||
}
|
||||
|
||||
int
|
||||
chk_bounds(l1, l2, fund)
|
||||
arith l1, l2;
|
||||
{
|
||||
/* compare to arith's, but be careful. They might be unsigned
|
||||
*/
|
||||
if (fund == T_INTEGER) {
|
||||
return l2 >= l1;
|
||||
}
|
||||
return (l2 & mach_long_sign ?
|
||||
(l1 & mach_long_sign ? l2 >= l1 : 1) :
|
||||
(l1 & mach_long_sign ? 0 : l2 >= l1)
|
||||
);
|
||||
}
|
||||
|
||||
struct type *
|
||||
subr_type(lb, ub)
|
||||
register struct node *lb;
|
||||
struct node *ub;
|
||||
{
|
||||
/* Construct a subrange type from the constant expressions
|
||||
indicated by "lb" and "ub", but first perform some
|
||||
checks
|
||||
*/
|
||||
register struct type *tp = BaseType(lb->nd_type);
|
||||
register struct type *res;
|
||||
|
||||
if (tp == intorcard_type) {
|
||||
/* Lower bound >= 0; in this case, the base type is CARDINAL,
|
||||
according to the language definition, par. 6.3
|
||||
*/
|
||||
assert(lb->nd_INT >= 0);
|
||||
tp = card_type;
|
||||
}
|
||||
|
||||
if (!ChkCompat(&ub, tp, "subrange bounds")) {
|
||||
return error_type;
|
||||
}
|
||||
|
||||
/* Check base type
|
||||
*/
|
||||
if (! (tp->tp_fund & T_DISCRETE)) {
|
||||
node_error(lb, "illegal base type for subrange");
|
||||
return error_type;
|
||||
}
|
||||
|
||||
/* Check bounds
|
||||
*/
|
||||
if (! chk_bounds(lb->nd_INT, ub->nd_INT, tp->tp_fund)) {
|
||||
node_error(lb, "lower bound exceeds upper bound");
|
||||
}
|
||||
|
||||
/* Now construct resulting type
|
||||
*/
|
||||
res = construct_type(T_SUBRANGE, tp);
|
||||
res->sub_lb = lb->nd_INT;
|
||||
res->sub_ub = ub->nd_INT;
|
||||
if (tp == card_type) {
|
||||
u_small(res, res->sub_ub);
|
||||
}
|
||||
else if (tp == int_type) {
|
||||
if (fit(res->sub_lb, 1) && fit(res->sub_ub, 1)) {
|
||||
res->tp_size = 1;
|
||||
res->tp_align = 1;
|
||||
}
|
||||
else if (fit(res->sub_lb, (int)short_size) &&
|
||||
fit(res->sub_ub, (int)short_size)) {
|
||||
res->tp_size = short_size;
|
||||
res->tp_align = short_align;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
struct type *
|
||||
proc_type(result_type, parameters, n_bytes_params)
|
||||
struct type *result_type;
|
||||
struct paramlist *parameters;
|
||||
arith n_bytes_params;
|
||||
{
|
||||
register struct type *tp = construct_type(T_PROCEDURE, result_type);
|
||||
|
||||
tp->prc_params = parameters;
|
||||
tp->prc_nbpar = n_bytes_params;
|
||||
return tp;
|
||||
}
|
||||
|
||||
genrck(tp)
|
||||
register struct type *tp;
|
||||
{
|
||||
/* generate a range check descriptor for type "tp" when
|
||||
neccessary. Return its label.
|
||||
*/
|
||||
arith lb, ub;
|
||||
register label ol;
|
||||
|
||||
getbounds(tp, &lb, &ub);
|
||||
|
||||
if (tp->tp_fund == T_SUBRANGE) {
|
||||
if (!(ol = tp->sub_rck)) {
|
||||
tp->sub_rck = ++data_label;
|
||||
}
|
||||
}
|
||||
else if (!(ol = tp->enm_rck)) {
|
||||
tp->enm_rck = ++data_label;
|
||||
}
|
||||
if (!ol) {
|
||||
C_df_dlb(ol = data_label);
|
||||
C_rom_cst(lb);
|
||||
C_rom_cst(ub);
|
||||
}
|
||||
C_lae_dlb(ol, (arith) 0);
|
||||
C_rck(word_size);
|
||||
}
|
||||
|
||||
getbounds(tp, plo, phi)
|
||||
register struct type *tp;
|
||||
arith *plo, *phi;
|
||||
{
|
||||
/* Get the bounds of a bounded type
|
||||
*/
|
||||
|
||||
assert(bounded(tp));
|
||||
|
||||
if (tp->tp_fund == T_SUBRANGE) {
|
||||
*plo = tp->sub_lb;
|
||||
*phi = tp->sub_ub;
|
||||
}
|
||||
else {
|
||||
*plo = 0;
|
||||
*phi = tp->enm_ncst - 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct type *
|
||||
set_type(tp)
|
||||
register struct type *tp;
|
||||
{
|
||||
/* Construct a set type with base type "tp", but first
|
||||
perform some checks
|
||||
*/
|
||||
arith lb, ub;
|
||||
|
||||
if (! bounded(tp)) {
|
||||
error("illegal base type for set");
|
||||
return error_type;
|
||||
}
|
||||
|
||||
getbounds(tp, &lb, &ub);
|
||||
|
||||
if (lb < 0 || ub > maxset-1 || (sizeof(int)==2 && ub > 65535)) {
|
||||
error("set type limits exceeded");
|
||||
return error_type;
|
||||
}
|
||||
|
||||
tp = construct_type(T_SET, tp);
|
||||
tp->tp_size = WA((ub + 8) >> 3);
|
||||
return tp;
|
||||
}
|
||||
|
||||
arith
|
||||
ArrayElSize(tp)
|
||||
register struct type *tp;
|
||||
{
|
||||
/* Align element size to alignment requirement of element type.
|
||||
Also make sure that its size is either a dividor of the word_size,
|
||||
or a multiple of it.
|
||||
*/
|
||||
register arith algn;
|
||||
|
||||
if (tp->tp_fund == T_ARRAY) ArraySizes(tp);
|
||||
algn = align(tp->tp_size, tp->tp_align);
|
||||
if (word_size % algn != 0) {
|
||||
/* algn is not a dividor of the word size, so make sure it
|
||||
is a multiple
|
||||
*/
|
||||
return WA(algn);
|
||||
}
|
||||
return algn;
|
||||
}
|
||||
|
||||
ArraySizes(tp)
|
||||
register struct type *tp;
|
||||
{
|
||||
/* Assign sizes to an array type, and check index type
|
||||
*/
|
||||
register struct type *index_type = IndexType(tp);
|
||||
register struct type *elem_type = tp->arr_elem;
|
||||
arith lo, hi, diff;
|
||||
|
||||
tp->arr_elsize = ArrayElSize(elem_type);
|
||||
tp->tp_align = elem_type->tp_align;
|
||||
|
||||
/* check index type
|
||||
*/
|
||||
if (! bounded(index_type)) {
|
||||
error("illegal index type");
|
||||
tp->tp_size = tp->arr_elsize;
|
||||
return;
|
||||
}
|
||||
|
||||
getbounds(index_type, &lo, &hi);
|
||||
diff = hi - lo;
|
||||
|
||||
tp->tp_size = (diff + 1) * tp->arr_elsize;
|
||||
|
||||
/* generate descriptor and remember label.
|
||||
*/
|
||||
tp->arr_descr = ++data_label;
|
||||
C_df_dlb(tp->arr_descr);
|
||||
C_rom_cst(lo);
|
||||
C_rom_cst(diff);
|
||||
C_rom_cst(tp->arr_elsize);
|
||||
}
|
||||
|
||||
FreeType(tp)
|
||||
register struct type *tp;
|
||||
{
|
||||
/* Release type structures indicated by "tp".
|
||||
This procedure is only called for types, constructed with
|
||||
T_PROCEDURE.
|
||||
*/
|
||||
register struct paramlist *pr, *pr1;
|
||||
|
||||
assert(tp->tp_fund == T_PROCEDURE);
|
||||
|
||||
pr = ParamList(tp);
|
||||
while (pr) {
|
||||
pr1 = pr;
|
||||
pr = pr->par_next;
|
||||
free_def(pr1->par_def);
|
||||
free_paramlist(pr1);
|
||||
}
|
||||
|
||||
free_type(tp);
|
||||
}
|
||||
|
||||
DeclareType(nd, df, tp)
|
||||
register struct def *df;
|
||||
register struct type *tp;
|
||||
struct node *nd;
|
||||
{
|
||||
/* A type with type-description "tp" is declared and must
|
||||
be bound to definition "df".
|
||||
This routine also handles the case that the type-field of
|
||||
"df" is already bound. In that case, it is either an opaque
|
||||
type, or an error message was given when "df" was created.
|
||||
*/
|
||||
register struct type *df_tp = df->df_type;
|
||||
|
||||
if (df_tp && df_tp->tp_fund == T_HIDDEN) {
|
||||
if (! (tp->tp_fund & (T_POINTER|T_HIDDEN|T_EQUAL))) {
|
||||
node_error(nd,
|
||||
"opaque type \"%s\" is not a pointer type",
|
||||
df->df_idf->id_text);
|
||||
}
|
||||
df_tp->tp_next = tp;
|
||||
df_tp->tp_fund = T_EQUAL;
|
||||
while (tp != df_tp && tp->tp_fund == T_EQUAL) {
|
||||
tp = tp->tp_next;
|
||||
}
|
||||
if (tp == df_tp) {
|
||||
/* Circular definition! */
|
||||
node_error(nd,
|
||||
"opaque type \"%s\" has a circular definition",
|
||||
df->df_idf->id_text);
|
||||
}
|
||||
}
|
||||
else df->df_type = tp;
|
||||
}
|
||||
|
||||
struct type *
|
||||
RemoveEqual(tpx)
|
||||
register struct type *tpx;
|
||||
{
|
||||
|
||||
if (tpx) while (tpx->tp_fund == T_EQUAL) tpx = tpx->tp_next;
|
||||
return tpx;
|
||||
}
|
||||
|
||||
int
|
||||
type_or_forward(ptp)
|
||||
struct type **ptp;
|
||||
{
|
||||
/* POINTER TO IDENTIFIER construction. The IDENTIFIER resides
|
||||
in "dot". This routine handles the different cases.
|
||||
*/
|
||||
register struct node *nd;
|
||||
register struct def *df, *df1;
|
||||
|
||||
if ((df1 = lookup(dot.TOK_IDF, CurrentScope, 1))) {
|
||||
/* Either a Module or a Type, but in both cases defined
|
||||
in this scope, so this is the correct identification
|
||||
*/
|
||||
if (df1->df_kind == D_FORWTYPE) {
|
||||
nd = new_node();
|
||||
nd->nd_token = dot;
|
||||
nd->nd_right = df1->df_forw_node;
|
||||
df1->df_forw_node = nd;
|
||||
nd->nd_type = *ptp;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
nd = new_node();
|
||||
nd->nd_token = dot;
|
||||
if ((df1 = lookfor(nd, CurrVis, 0))->df_kind == D_MODULE) {
|
||||
/* A Modulename in one of the enclosing scopes.
|
||||
It is not clear from the language definition that
|
||||
it is correct to handle these like this, but
|
||||
existing compilers do it like this, and the
|
||||
alternative is difficult with a lookahead of only
|
||||
one token.
|
||||
???
|
||||
*/
|
||||
free_node(nd);
|
||||
return 1;
|
||||
}
|
||||
/* Enter a forward reference into a list belonging to the
|
||||
current scope. This is used for POINTER declarations, which
|
||||
may have forward references that must howewer be declared in the
|
||||
same scope.
|
||||
*/
|
||||
df = define(nd->nd_IDF, CurrentScope, D_FORWTYPE);
|
||||
|
||||
if (df->df_kind == D_TYPE) {
|
||||
(*ptp)->tp_next = df->df_type;
|
||||
free_node(nd);
|
||||
return 0;
|
||||
}
|
||||
nd->nd_type = *ptp;
|
||||
df->df_forw_node = nd;
|
||||
if (df1->df_kind == D_TYPE) {
|
||||
df->df_type = df1->df_type;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
gcd(m, n)
|
||||
register int m, n;
|
||||
{
|
||||
/* Greatest Common Divisor
|
||||
*/
|
||||
register int r;
|
||||
|
||||
while (n) {
|
||||
r = m % n;
|
||||
m = n;
|
||||
n = r;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
int
|
||||
lcm(m, n)
|
||||
int m, n;
|
||||
{
|
||||
/* Least Common Multiple
|
||||
*/
|
||||
return m * (n / gcd(m, n));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
DumpType(tp)
|
||||
register struct type *tp;
|
||||
{
|
||||
if (!tp) return;
|
||||
|
||||
print("align:%d; size:%ld;", tp->tp_align, (long) tp->tp_size);
|
||||
|
||||
print(" fund:");
|
||||
switch(tp->tp_fund) {
|
||||
case T_RECORD:
|
||||
print("RECORD");
|
||||
break;
|
||||
case T_ENUMERATION:
|
||||
print("ENUMERATION; ncst:%d", tp->enm_ncst); break;
|
||||
case T_INTEGER:
|
||||
print("INTEGER"); break;
|
||||
case T_CARDINAL:
|
||||
print("CARDINAL"); break;
|
||||
case T_REAL:
|
||||
print("REAL"); break;
|
||||
case T_HIDDEN:
|
||||
print("HIDDEN"); break;
|
||||
case T_EQUAL:
|
||||
print("EQUAL"); break;
|
||||
case T_POINTER:
|
||||
print("POINTER"); break;
|
||||
case T_CHAR:
|
||||
print("CHAR"); break;
|
||||
case T_WORD:
|
||||
print("WORD"); break;
|
||||
case T_SET:
|
||||
print("SET"); break;
|
||||
case T_SUBRANGE:
|
||||
print("SUBRANGE %ld-%ld", (long) tp->sub_lb, (long) tp->sub_ub);
|
||||
break;
|
||||
case T_PROCEDURE:
|
||||
{
|
||||
register struct paramlist *par = ParamList(tp);
|
||||
|
||||
print("PROCEDURE");
|
||||
if (par) {
|
||||
print("(");
|
||||
while(par) {
|
||||
if (IsVarParam(par)) print("VAR ");
|
||||
DumpType(TypeOfParam(par));
|
||||
par = par->par_next;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case T_ARRAY:
|
||||
print("ARRAY");
|
||||
print("; element:");
|
||||
DumpType(tp->arr_elem);
|
||||
print("; index:");
|
||||
DumpType(tp->tp_next);
|
||||
print(";");
|
||||
return;
|
||||
case T_STRING:
|
||||
print("STRING"); break;
|
||||
case T_INTORCARD:
|
||||
print("INTORCARD"); break;
|
||||
default:
|
||||
crash("DumpType");
|
||||
}
|
||||
if (tp->tp_next && tp->tp_fund != T_POINTER) {
|
||||
/* Avoid printing recursive types!
|
||||
*/
|
||||
print(" next:(");
|
||||
DumpType(tp->tp_next);
|
||||
print(")");
|
||||
}
|
||||
print(";");
|
||||
}
|
||||
#endif
|
||||
298
lang/m2/comp/typequiv.c
Normal file
298
lang/m2/comp/typequiv.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* T Y P E E Q U I V A L E N C E */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* Routines for testing type equivalence, type compatibility, and
|
||||
assignment compatibility
|
||||
*/
|
||||
#include "debug.h"
|
||||
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "type.h"
|
||||
#include "LLlex.h"
|
||||
#include "idf.h"
|
||||
#include "def.h"
|
||||
#include "node.h"
|
||||
#include "warning.h"
|
||||
|
||||
extern char *sprint();
|
||||
|
||||
int
|
||||
TstTypeEquiv(tp1, tp2)
|
||||
struct type *tp1, *tp2;
|
||||
{
|
||||
/* test if two types are equivalent.
|
||||
*/
|
||||
|
||||
return tp1 == tp2
|
||||
||
|
||||
tp1 == error_type
|
||||
||
|
||||
tp2 == error_type;
|
||||
}
|
||||
|
||||
int
|
||||
TstParEquiv(tp1, tp2)
|
||||
register struct type *tp1, *tp2;
|
||||
{
|
||||
/* test if two parameter types are equivalent. This routine
|
||||
is used to check if two different procedure declarations
|
||||
(one in the definition module, one in the implementation
|
||||
module) are equivalent. A complication comes from dynamic
|
||||
arrays.
|
||||
*/
|
||||
|
||||
return
|
||||
TstTypeEquiv(tp1, tp2)
|
||||
||
|
||||
(
|
||||
IsConformantArray(tp1)
|
||||
&&
|
||||
IsConformantArray(tp2)
|
||||
&&
|
||||
TstTypeEquiv(tp1->arr_elem, tp2->arr_elem)
|
||||
);
|
||||
}
|
||||
|
||||
int
|
||||
TstProcEquiv(tp1, tp2)
|
||||
struct type *tp1, *tp2;
|
||||
{
|
||||
/* Test if two procedure types are equivalent. This routine
|
||||
may also be used for the testing of assignment compatibility
|
||||
between procedure variables and procedures.
|
||||
*/
|
||||
register struct paramlist *p1, *p2;
|
||||
|
||||
/* First check if the result types are equivalent
|
||||
*/
|
||||
if (! TstTypeEquiv(ResultType(tp1), ResultType(tp2))) return 0;
|
||||
|
||||
p1 = ParamList(tp1);
|
||||
p2 = ParamList(tp2);
|
||||
|
||||
/* Now check the parameters
|
||||
*/
|
||||
while (p1 && p2) {
|
||||
if (IsVarParam(p1) != IsVarParam(p2) ||
|
||||
!TstParEquiv(TypeOfParam(p1), TypeOfParam(p2))) return 0;
|
||||
p1 = p1->par_next;
|
||||
p2 = p2->par_next;
|
||||
}
|
||||
|
||||
/* Here, at least one of the parameterlists is exhausted.
|
||||
Check that they are both.
|
||||
*/
|
||||
return p1 == p2;
|
||||
}
|
||||
|
||||
int
|
||||
TstCompat(tp1, tp2)
|
||||
register struct type *tp1, *tp2;
|
||||
{
|
||||
/* test if two types are compatible. See section 6.3 of the
|
||||
Modula-2 Report for a definition of "compatible".
|
||||
*/
|
||||
|
||||
if (TstTypeEquiv(tp1, tp2)) return 1;
|
||||
|
||||
tp1 = BaseType(tp1);
|
||||
tp2 = BaseType(tp2);
|
||||
if (tp2 != intorcard_type &&
|
||||
(tp1 == intorcard_type || tp1 == address_type)) {
|
||||
struct type *tmp = tp2;
|
||||
|
||||
tp2 = tp1;
|
||||
tp1 = tmp;
|
||||
}
|
||||
|
||||
return tp1 == tp2
|
||||
||
|
||||
( tp2 == intorcard_type
|
||||
&&
|
||||
(tp1 == int_type || tp1 == card_type || tp1 == address_type)
|
||||
)
|
||||
||
|
||||
( tp2 == address_type
|
||||
&&
|
||||
( tp1 == card_type || tp1->tp_fund == T_POINTER)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
int
|
||||
TstAssCompat(tp1, tp2)
|
||||
register struct type *tp1, *tp2;
|
||||
{
|
||||
/* Test if two types are assignment compatible.
|
||||
See Def 9.1.
|
||||
*/
|
||||
register struct type *tp;
|
||||
|
||||
if (TstCompat(tp1, tp2)) return 1;
|
||||
|
||||
tp1 = BaseType(tp1);
|
||||
tp2 = BaseType(tp2);
|
||||
|
||||
if ((tp1->tp_fund & T_INTORCARD) &&
|
||||
(tp2->tp_fund & T_INTORCARD)) return 1;
|
||||
|
||||
if ((tp1->tp_fund == T_REAL) &&
|
||||
(tp2->tp_fund == T_REAL)) return 1;
|
||||
|
||||
if (tp1->tp_fund == T_PROCEDURE &&
|
||||
tp2->tp_fund == T_PROCEDURE) {
|
||||
return TstProcEquiv(tp1, tp2);
|
||||
}
|
||||
|
||||
if (tp1->tp_fund == T_ARRAY) {
|
||||
/* check for string
|
||||
*/
|
||||
arith size;
|
||||
|
||||
if (IsConformantArray(tp1)) return 0;
|
||||
|
||||
tp = IndexType(tp1);
|
||||
if (tp->tp_fund == T_SUBRANGE) {
|
||||
size = tp->sub_ub - tp->sub_lb + 1;
|
||||
}
|
||||
else size = tp->enm_ncst;
|
||||
tp1 = BaseType(tp1->arr_elem);
|
||||
return
|
||||
tp1 == char_type
|
||||
&& (tp2->tp_fund == T_STRING && size >= tp2->tp_size)
|
||||
;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
TstParCompat(parno, formaltype, VARflag, nd, edf)
|
||||
register struct type *formaltype;
|
||||
struct node **nd;
|
||||
struct def *edf;
|
||||
{
|
||||
/* Check type compatibility for a parameter in a procedure call.
|
||||
Assignment compatibility may do if the parameter is
|
||||
a value parameter.
|
||||
Otherwise, a conformant array may do, or an ARRAY OF (WORD|BYTE)
|
||||
may do too.
|
||||
Or: a WORD may do.
|
||||
*/
|
||||
register struct type *actualtype = (*nd)->nd_type;
|
||||
char ebuf[256];
|
||||
char ebuf1[256];
|
||||
|
||||
if (edf) {
|
||||
sprint(ebuf, "\"%s\", parameter %d: %%s", edf->df_idf->id_text, parno);
|
||||
}
|
||||
else sprint(ebuf, "parameter %d: %%s", parno);
|
||||
|
||||
if (
|
||||
TstTypeEquiv(formaltype, actualtype)
|
||||
||
|
||||
( !VARflag && ChkAssCompat(nd, formaltype, (char *) 0))
|
||||
||
|
||||
( formaltype == address_type
|
||||
&& actualtype->tp_fund == T_POINTER
|
||||
)
|
||||
||
|
||||
( formaltype == word_type
|
||||
&&
|
||||
( actualtype->tp_size == word_size
|
||||
||
|
||||
( !VARflag
|
||||
&&
|
||||
actualtype->tp_size <= word_size
|
||||
)
|
||||
)
|
||||
)
|
||||
||
|
||||
( formaltype == byte_type
|
||||
&& actualtype->tp_size == (arith) 1
|
||||
)
|
||||
||
|
||||
( IsConformantArray(formaltype)
|
||||
&&
|
||||
( formaltype->arr_elem == word_type
|
||||
|| formaltype->arr_elem == byte_type
|
||||
||
|
||||
( actualtype->tp_fund == T_ARRAY
|
||||
&& TstTypeEquiv(formaltype->arr_elem,actualtype->arr_elem)
|
||||
)
|
||||
||
|
||||
( actualtype->tp_fund == T_STRING
|
||||
&& TstTypeEquiv(formaltype->arr_elem, char_type)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
return 1;
|
||||
if (VARflag && TstCompat(formaltype, actualtype)) {
|
||||
if (formaltype->tp_size == actualtype->tp_size) {
|
||||
sprint(ebuf1, ebuf, "identical types required");
|
||||
node_warning(*nd,
|
||||
W_OLDFASHIONED,
|
||||
ebuf1);
|
||||
return 1;
|
||||
}
|
||||
sprint(ebuf1, ebuf, "equal sized types required");
|
||||
node_error(*nd, ebuf1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sprint(ebuf1, ebuf, "type incompatibility");
|
||||
node_error(*nd, ebuf1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CompatCheck(nd, tp, message, fc)
|
||||
struct node **nd;
|
||||
struct type *tp;
|
||||
char *message;
|
||||
int (*fc)();
|
||||
{
|
||||
if (! (*fc)(tp, (*nd)->nd_type)) {
|
||||
if (message) {
|
||||
node_error(*nd, "type incompatibility in %s", message);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
MkCoercion(nd, tp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ChkAssCompat(nd, tp, message)
|
||||
struct node **nd;
|
||||
struct type *tp;
|
||||
char *message;
|
||||
{
|
||||
/* Check assignment compatibility of node "nd" with type "tp".
|
||||
Give an error message when it fails
|
||||
*/
|
||||
|
||||
return CompatCheck(nd, tp, message, TstAssCompat);
|
||||
}
|
||||
|
||||
ChkCompat(nd, tp, message)
|
||||
struct node **nd;
|
||||
struct type *tp;
|
||||
char *message;
|
||||
{
|
||||
/* Check compatibility of node "nd" with type "tp".
|
||||
Give an error message when it fails
|
||||
*/
|
||||
|
||||
return CompatCheck(nd, tp, message, TstCompat);
|
||||
}
|
||||
811
lang/m2/comp/walk.c
Normal file
811
lang/m2/comp/walk.c
Normal file
@@ -0,0 +1,811 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* P A R S E T R E E W A L K E R */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* Routines to walk through parts of the parse tree, and generate
|
||||
code for these parts.
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <em_arith.h>
|
||||
#include <em_label.h>
|
||||
#include <em_reg.h>
|
||||
#include <em_code.h>
|
||||
#include <m2_traps.h>
|
||||
#include <assert.h>
|
||||
#include <alloc.h>
|
||||
|
||||
#include "LLlex.h"
|
||||
#include "def.h"
|
||||
#include "type.h"
|
||||
#include "scope.h"
|
||||
#include "main.h"
|
||||
#include "node.h"
|
||||
#include "Lpars.h"
|
||||
#include "desig.h"
|
||||
#include "f_info.h"
|
||||
#include "idf.h"
|
||||
#include "chk_expr.h"
|
||||
#include "walk.h"
|
||||
#include "warning.h"
|
||||
|
||||
extern arith NewPtr();
|
||||
extern arith NewInt();
|
||||
extern int proclevel;
|
||||
label text_label;
|
||||
label data_label = 1;
|
||||
static struct type *func_type;
|
||||
struct withdesig *WithDesigs;
|
||||
struct node *Modules;
|
||||
static struct node *priority;
|
||||
|
||||
#define NO_EXIT_LABEL ((label) 0)
|
||||
#define RETURN_LABEL ((label) 1)
|
||||
|
||||
STATIC
|
||||
DoPriority()
|
||||
{
|
||||
/* For the time being (???), handle priorities by calls to
|
||||
the runtime system
|
||||
*/
|
||||
|
||||
register struct node *p;
|
||||
|
||||
if (p = priority) {
|
||||
C_loc(p->nd_INT);
|
||||
C_cal("_stackprio");
|
||||
C_asp(word_size);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
EndPriority()
|
||||
{
|
||||
if (priority) {
|
||||
C_cal("_unstackprio");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
DoProfil()
|
||||
{
|
||||
static label filename_label = 0;
|
||||
|
||||
if (! options['L']) {
|
||||
|
||||
if (! filename_label) {
|
||||
filename_label = 1;
|
||||
C_df_dlb((label) 1);
|
||||
C_rom_scon(FileName, (arith) (strlen(FileName) + 1));
|
||||
}
|
||||
|
||||
C_fil_dlb((label) 1, (arith) 0);
|
||||
}
|
||||
}
|
||||
|
||||
WalkModule(module)
|
||||
register struct def *module;
|
||||
{
|
||||
/* Walk through a module, and all its local definitions.
|
||||
Also generate code for its body.
|
||||
This code is collected in an initialization routine.
|
||||
*/
|
||||
register struct scope *sc;
|
||||
struct scopelist *savevis = CurrVis;
|
||||
|
||||
CurrVis = module->mod_vis;
|
||||
priority = module->mod_priority;
|
||||
sc = CurrentScope;
|
||||
|
||||
/* Walk through it's local definitions
|
||||
*/
|
||||
WalkDef(sc->sc_def);
|
||||
|
||||
/* Now, generate initialization code for this module.
|
||||
First call initialization routines for modules defined within
|
||||
this module.
|
||||
*/
|
||||
sc->sc_off = 0; /* no locals (yet) */
|
||||
text_label = 1; /* label at end of initialization routine */
|
||||
TmpOpen(sc); /* Initialize for temporaries */
|
||||
C_pro_narg(sc->sc_name);
|
||||
DoPriority();
|
||||
DoProfil();
|
||||
if (module == Defined) {
|
||||
/* Body of implementation or program module.
|
||||
Call initialization routines of imported modules.
|
||||
Also prevent recursive calls of this one.
|
||||
*/
|
||||
register struct node *nd = Modules;
|
||||
|
||||
if (state == IMPLEMENTATION) {
|
||||
/* We don't actually prevent recursive calls,
|
||||
but do nothing if called recursively
|
||||
*/
|
||||
C_df_dlb(++data_label);
|
||||
C_con_cst((arith) 0);
|
||||
/* if this one is set to non-zero, the initialization
|
||||
was already done.
|
||||
*/
|
||||
C_loe_dlb(data_label, (arith) 0);
|
||||
C_zne(RETURN_LABEL);
|
||||
C_ine_dlb(data_label, (arith) 0);
|
||||
}
|
||||
|
||||
for (; nd; nd = nd->nd_left) {
|
||||
C_cal(nd->nd_IDF->id_text);
|
||||
}
|
||||
}
|
||||
MkCalls(sc->sc_def);
|
||||
proclevel++;
|
||||
WalkNode(module->mod_body, NO_EXIT_LABEL);
|
||||
DO_DEBUG(options['X'], PrNode(module->mod_body, 0));
|
||||
C_df_ilb(RETURN_LABEL);
|
||||
EndPriority();
|
||||
C_ret((arith) 0);
|
||||
C_end(-sc->sc_off);
|
||||
proclevel--;
|
||||
TmpClose();
|
||||
|
||||
CurrVis = savevis;
|
||||
}
|
||||
|
||||
WalkProcedure(procedure)
|
||||
register struct def *procedure;
|
||||
{
|
||||
/* Walk through the definition of a procedure and all its
|
||||
local definitions, checking and generating code.
|
||||
*/
|
||||
struct scopelist *savevis = CurrVis;
|
||||
register struct scope *sc = procedure->prc_vis->sc_scope;
|
||||
register struct type *tp;
|
||||
register struct paramlist *param;
|
||||
label func_res_label = 0;
|
||||
arith StackAdjustment = 0;
|
||||
arith retsav = 0;
|
||||
arith func_res_size = 0;
|
||||
|
||||
proclevel++;
|
||||
CurrVis = procedure->prc_vis;
|
||||
|
||||
/* Generate code for all local modules and procedures
|
||||
*/
|
||||
WalkDef(sc->sc_def);
|
||||
|
||||
/* Generate code for this procedure
|
||||
*/
|
||||
C_pro_narg(sc->sc_name);
|
||||
DoPriority();
|
||||
DoProfil();
|
||||
TmpOpen(sc);
|
||||
|
||||
func_type = tp = RemoveEqual(ResultType(procedure->df_type));
|
||||
|
||||
if (tp) {
|
||||
func_res_size = WA(tp->tp_size);
|
||||
if (IsConstructed(tp)) {
|
||||
/* The result type of this procedure is constructed.
|
||||
The actual procedure will return a pointer to a
|
||||
global data area in which the function result is
|
||||
stored.
|
||||
Notice that this does make the code non-reentrant.
|
||||
Here, we create the data area for the function
|
||||
result.
|
||||
*/
|
||||
func_res_label = ++data_label;
|
||||
C_df_dlb(func_res_label);
|
||||
C_bss_cst(func_res_size, (arith) 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate calls to initialization routines of modules defined within
|
||||
this procedure
|
||||
*/
|
||||
MkCalls(sc->sc_def);
|
||||
|
||||
/* Make sure that arguments of size < word_size are on a
|
||||
fixed place.
|
||||
Also make copies of conformant arrays when neccessary.
|
||||
*/
|
||||
for (param = ParamList(procedure->df_type);
|
||||
param;
|
||||
param = param->par_next) {
|
||||
if (! IsVarParam(param)) {
|
||||
tp = TypeOfParam(param);
|
||||
|
||||
if (! IsConformantArray(tp)) {
|
||||
if (tp->tp_size < word_size &&
|
||||
(int) word_size % (int) tp->tp_size == 0) {
|
||||
C_lol(param->par_def->var_off);
|
||||
C_lal(param->par_def->var_off);
|
||||
C_sti(tp->tp_size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Here, we have to make a copy of the
|
||||
array. We must also remember how much
|
||||
room is reserved for copies, because
|
||||
we have to adjust the stack pointer before
|
||||
a RET is done. This is even more complicated
|
||||
when the procedure returns a value.
|
||||
Then, the value must be saved (in retval),
|
||||
the stack adjusted, the return value pushed
|
||||
again, and then RET
|
||||
*/
|
||||
if (! StackAdjustment) {
|
||||
/* First time we get here
|
||||
*/
|
||||
if (func_type && !func_res_label) {
|
||||
/* Some local space, only
|
||||
needed if the value itself
|
||||
is returned
|
||||
*/
|
||||
sc->sc_off -= func_res_size;
|
||||
retsav = sc->sc_off;
|
||||
}
|
||||
StackAdjustment = NewPtr();
|
||||
C_lor((arith) 1);
|
||||
C_stl(StackAdjustment);
|
||||
}
|
||||
/* First compute new stackpointer */
|
||||
C_lal(param->par_def->var_off);
|
||||
C_cal("_new_stackptr");
|
||||
C_asp(pointer_size);
|
||||
C_lfr(pointer_size);
|
||||
C_str((arith) 1);
|
||||
/* adjusted stack pointer */
|
||||
C_lol(param->par_def->var_off);
|
||||
/* push source address */
|
||||
C_cal("_copy_array");
|
||||
/* copy */
|
||||
C_asp(word_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
text_label = 1; /* label at end of procedure */
|
||||
|
||||
WalkNode(procedure->prc_body, NO_EXIT_LABEL);
|
||||
DO_DEBUG(options['X'], PrNode(procedure->prc_body, 0));
|
||||
if (func_res_size) {
|
||||
C_loc((arith) M2_NORESULT);
|
||||
C_trp();
|
||||
C_asp(-func_res_size);
|
||||
}
|
||||
C_df_ilb(RETURN_LABEL); /* label at end */
|
||||
if (func_res_label) {
|
||||
/* Fill the data area reserved for the function result
|
||||
with the result
|
||||
*/
|
||||
C_lae_dlb(func_res_label, (arith) 0);
|
||||
C_sti(func_res_size);
|
||||
if (StackAdjustment) {
|
||||
/* Remove copies of conformant arrays
|
||||
*/
|
||||
C_lol(StackAdjustment);
|
||||
C_str((arith) 1);
|
||||
}
|
||||
C_lae_dlb(func_res_label, (arith) 0);
|
||||
func_res_size = pointer_size;
|
||||
}
|
||||
else if (StackAdjustment) {
|
||||
/* First save the function result in a safe place.
|
||||
Then remove copies of conformant arrays,
|
||||
and put function result back on the stack
|
||||
*/
|
||||
if (func_type) {
|
||||
C_lal(retsav);
|
||||
C_sti(func_res_size);
|
||||
}
|
||||
C_lol(StackAdjustment);
|
||||
C_str((arith) 1);
|
||||
if (func_type) {
|
||||
C_lal(retsav);
|
||||
C_loi(func_res_size);
|
||||
}
|
||||
FreePtr(StackAdjustment);
|
||||
}
|
||||
EndPriority();
|
||||
C_ret(func_res_size);
|
||||
if (! options['n']) RegisterMessages(sc->sc_def);
|
||||
C_end(-sc->sc_off);
|
||||
TmpClose();
|
||||
CurrVis = savevis;
|
||||
proclevel--;
|
||||
}
|
||||
|
||||
WalkDef(df)
|
||||
register struct def *df;
|
||||
{
|
||||
/* Walk through a list of definitions
|
||||
*/
|
||||
|
||||
for ( ; df; df = df->df_nextinscope) {
|
||||
switch(df->df_kind) {
|
||||
case D_MODULE:
|
||||
WalkModule(df);
|
||||
break;
|
||||
case D_PROCEDURE:
|
||||
WalkProcedure(df);
|
||||
break;
|
||||
case D_VARIABLE:
|
||||
if (!proclevel && !(df->df_flags & D_ADDRGIVEN)) {
|
||||
C_df_dnam(df->var_name);
|
||||
C_bss_cst(
|
||||
WA(df->df_type->tp_size),
|
||||
(arith) 0, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* nothing */
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MkCalls(df)
|
||||
register struct def *df;
|
||||
{
|
||||
/* Generate calls to initialization routines of modules
|
||||
*/
|
||||
|
||||
for ( ; df; df = df->df_nextinscope) {
|
||||
if (df->df_kind == D_MODULE) {
|
||||
C_lxl((arith) 0);
|
||||
C_cal(df->mod_vis->sc_scope->sc_name);
|
||||
C_asp(pointer_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WalkLink(nd, exit_label)
|
||||
register struct node *nd;
|
||||
label exit_label;
|
||||
{
|
||||
/* Walk node "nd", which is a link.
|
||||
*/
|
||||
|
||||
while (nd && nd->nd_class == Link) { /* statement list */
|
||||
WalkNode(nd->nd_left, exit_label);
|
||||
nd = nd->nd_right;
|
||||
}
|
||||
|
||||
WalkNode(nd, exit_label);
|
||||
}
|
||||
|
||||
WalkCall(nd)
|
||||
register struct node *nd;
|
||||
{
|
||||
assert(nd->nd_class == Call);
|
||||
|
||||
if (! options['L']) C_lin((arith) nd->nd_lineno);
|
||||
if (ChkCall(nd)) {
|
||||
if (nd->nd_type != 0) {
|
||||
node_error(nd, "procedure call expected");
|
||||
return;
|
||||
}
|
||||
CodeCall(nd);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
ForLoopVarExpr(nd)
|
||||
register struct node *nd;
|
||||
{
|
||||
register struct type *tp = nd->nd_type;
|
||||
|
||||
CodePExpr(nd);
|
||||
CodeCoercion(tp, BaseType(tp));
|
||||
}
|
||||
|
||||
WalkStat(nd, exit_label)
|
||||
register struct node *nd;
|
||||
label exit_label;
|
||||
{
|
||||
/* Walk through a statement, generating code for it.
|
||||
*/
|
||||
register struct node *left = nd->nd_left;
|
||||
register struct node *right = nd->nd_right;
|
||||
|
||||
assert(nd->nd_class == Stat);
|
||||
|
||||
if (! options['L'] && nd->nd_lineno) C_lin((arith) nd->nd_lineno);
|
||||
switch(nd->nd_symb) {
|
||||
case ';':
|
||||
break;
|
||||
|
||||
case BECOMES:
|
||||
DoAssign(left, right);
|
||||
break;
|
||||
|
||||
case IF:
|
||||
{ label l1 = ++text_label, l3 = ++text_label;
|
||||
|
||||
ExpectBool(left, l3, l1);
|
||||
assert(right->nd_symb == THEN);
|
||||
C_df_ilb(l3);
|
||||
WalkNode(right->nd_left, exit_label);
|
||||
|
||||
if (right->nd_right) { /* ELSE part */
|
||||
label l2 = ++text_label;
|
||||
|
||||
C_bra(l2);
|
||||
C_df_ilb(l1);
|
||||
WalkNode(right->nd_right, exit_label);
|
||||
l1 = l2;
|
||||
}
|
||||
C_df_ilb(l1);
|
||||
break;
|
||||
}
|
||||
|
||||
case CASE:
|
||||
CaseCode(nd, exit_label);
|
||||
break;
|
||||
|
||||
case WHILE:
|
||||
{ label loop = ++text_label,
|
||||
exit = ++text_label,
|
||||
dummy = ++text_label;
|
||||
|
||||
C_df_ilb(loop);
|
||||
ExpectBool(left, dummy, exit);
|
||||
C_df_ilb(dummy);
|
||||
WalkNode(right, exit_label);
|
||||
C_bra(loop);
|
||||
C_df_ilb(exit);
|
||||
break;
|
||||
}
|
||||
|
||||
case REPEAT:
|
||||
{ label loop = ++text_label, exit = ++text_label;
|
||||
|
||||
C_df_ilb(loop);
|
||||
WalkNode(left, exit_label);
|
||||
ExpectBool(right, exit, loop);
|
||||
C_df_ilb(exit);
|
||||
break;
|
||||
}
|
||||
|
||||
case LOOP:
|
||||
{ label loop = ++text_label, exit = ++text_label;
|
||||
|
||||
C_df_ilb(loop);
|
||||
WalkNode(right, exit);
|
||||
C_bra(loop);
|
||||
C_df_ilb(exit);
|
||||
break;
|
||||
}
|
||||
|
||||
case FOR:
|
||||
{
|
||||
arith tmp = 0;
|
||||
register struct node *fnd;
|
||||
int good_forvar;
|
||||
label l1 = ++text_label;
|
||||
label l2 = ++text_label;
|
||||
int uns = 0;
|
||||
arith stepsize;
|
||||
struct type *bstp;
|
||||
|
||||
good_forvar = DoForInit(nd);
|
||||
if ((stepsize = left->nd_INT) == 0) {
|
||||
node_warning(left,
|
||||
W_ORDINARY,
|
||||
"zero stepsize in FOR loop");
|
||||
}
|
||||
fnd = left->nd_right;
|
||||
if (good_forvar) {
|
||||
bstp = BaseType(nd->nd_type);
|
||||
uns = bstp->tp_fund != T_INTEGER;
|
||||
C_dup(int_size);
|
||||
RangeCheck(left->nd_left->nd_type, nd->nd_type);
|
||||
CodeDStore(nd);
|
||||
CodePExpr(fnd);
|
||||
tmp = NewInt();
|
||||
C_stl(tmp);
|
||||
C_lol(tmp);
|
||||
if (uns) C_cmu(int_size);
|
||||
else C_cmi(int_size);
|
||||
if (left->nd_INT >= 0) {
|
||||
C_zgt(l2);
|
||||
C_lol(tmp);
|
||||
ForLoopVarExpr(nd);
|
||||
}
|
||||
else {
|
||||
stepsize = -stepsize;
|
||||
C_zlt(l2);
|
||||
ForLoopVarExpr(nd);
|
||||
C_lol(tmp);
|
||||
}
|
||||
C_sbu(int_size);
|
||||
if (stepsize) {
|
||||
C_loc(stepsize);
|
||||
C_dvu(int_size);
|
||||
}
|
||||
C_stl(tmp);
|
||||
nd->nd_def->df_flags |= D_FORLOOP;
|
||||
C_df_ilb(l1);
|
||||
}
|
||||
WalkNode(right, exit_label);
|
||||
nd->nd_def->df_flags &= ~D_FORLOOP;
|
||||
if (good_forvar && stepsize) {
|
||||
C_lol(tmp);
|
||||
C_zeq(l2);
|
||||
C_lol(tmp);
|
||||
C_loc((arith) 1);
|
||||
C_sbu(int_size);
|
||||
C_stl(tmp);
|
||||
C_loc(left->nd_INT);
|
||||
ForLoopVarExpr(nd);
|
||||
C_adu(int_size);
|
||||
RangeCheck(bstp, nd->nd_type);
|
||||
CodeDStore(nd);
|
||||
}
|
||||
C_bra(l1);
|
||||
C_df_ilb(l2);
|
||||
FreeInt(tmp);
|
||||
#ifdef DEBUG
|
||||
nd->nd_left = left;
|
||||
nd->nd_right = right;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case WITH:
|
||||
{
|
||||
struct scopelist link;
|
||||
struct withdesig wds;
|
||||
struct desig ds;
|
||||
|
||||
if (! WalkDesignator(left, &ds)) break;
|
||||
if (left->nd_type->tp_fund != T_RECORD) {
|
||||
node_error(left, "record variable expected");
|
||||
break;
|
||||
}
|
||||
|
||||
wds.w_next = WithDesigs;
|
||||
WithDesigs = &wds;
|
||||
wds.w_scope = left->nd_type->rec_scope;
|
||||
CodeAddress(&ds);
|
||||
ds.dsg_kind = DSG_FIXED;
|
||||
/* Create a designator structure for the temporary.
|
||||
*/
|
||||
ds.dsg_offset = NewPtr();
|
||||
ds.dsg_name = 0;
|
||||
CodeStore(&ds, address_type);
|
||||
ds.dsg_kind = DSG_PFIXED;
|
||||
/* the record is indirectly available */
|
||||
wds.w_desig = ds;
|
||||
link.sc_scope = wds.w_scope;
|
||||
link.sc_next = CurrVis;
|
||||
CurrVis = &link;
|
||||
WalkNode(right, exit_label);
|
||||
CurrVis = link.sc_next;
|
||||
WithDesigs = wds.w_next;
|
||||
FreePtr(ds.dsg_offset);
|
||||
break;
|
||||
}
|
||||
|
||||
case EXIT:
|
||||
assert(exit_label != 0);
|
||||
|
||||
C_bra(exit_label);
|
||||
break;
|
||||
|
||||
case RETURN:
|
||||
if (right) {
|
||||
if (! ChkExpression(right)) break;
|
||||
/* The type of the return-expression must be
|
||||
assignment compatible with the result type of the
|
||||
function procedure (See Rep. 9.11).
|
||||
*/
|
||||
if (!ChkAssCompat(&(nd->nd_right), func_type, "RETURN")) {
|
||||
break;
|
||||
}
|
||||
right = nd->nd_right;
|
||||
if (right->nd_type->tp_fund == T_STRING) {
|
||||
CodePString(right, func_type);
|
||||
}
|
||||
else CodePExpr(right);
|
||||
}
|
||||
C_bra(RETURN_LABEL);
|
||||
break;
|
||||
|
||||
default:
|
||||
crash("(WalkStat)");
|
||||
}
|
||||
}
|
||||
|
||||
extern int NodeCrash();
|
||||
|
||||
STATIC
|
||||
WalkOption(nd)
|
||||
struct node *nd;
|
||||
{
|
||||
/* Set option indicated by node "nd"
|
||||
*/
|
||||
|
||||
options[nd->nd_symb] = nd->nd_INT;
|
||||
}
|
||||
|
||||
int (*WalkTable[])() = {
|
||||
NodeCrash,
|
||||
NodeCrash,
|
||||
NodeCrash,
|
||||
NodeCrash,
|
||||
NodeCrash,
|
||||
WalkCall,
|
||||
NodeCrash,
|
||||
NodeCrash,
|
||||
NodeCrash,
|
||||
NodeCrash,
|
||||
WalkStat,
|
||||
WalkLink,
|
||||
WalkOption
|
||||
};
|
||||
|
||||
ExpectBool(nd, true_label, false_label)
|
||||
register struct node *nd;
|
||||
label true_label, false_label;
|
||||
{
|
||||
/* "nd" must indicate a boolean expression. Check this and
|
||||
generate code to evaluate the expression.
|
||||
*/
|
||||
register struct desig *ds = new_desig();
|
||||
|
||||
if (ChkExpression(nd)) {
|
||||
if (nd->nd_type != bool_type && nd->nd_type != error_type) {
|
||||
node_error(nd, "boolean expression expected");
|
||||
}
|
||||
|
||||
CodeExpr(nd, ds, true_label, false_label);
|
||||
}
|
||||
free_desig(ds);
|
||||
}
|
||||
|
||||
int
|
||||
WalkDesignator(nd, ds)
|
||||
struct node *nd;
|
||||
struct desig *ds;
|
||||
{
|
||||
/* Check designator and generate code for it
|
||||
*/
|
||||
|
||||
if (! ChkVariable(nd)) return 0;
|
||||
|
||||
clear((char *) ds, sizeof(struct desig));
|
||||
CodeDesig(nd, ds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DoForInit(nd)
|
||||
register struct node *nd;
|
||||
{
|
||||
register struct node *left = nd->nd_left;
|
||||
register struct def *df;
|
||||
struct type *tpl, *tpr;
|
||||
|
||||
nd->nd_left = nd->nd_right = 0;
|
||||
nd->nd_class = Name;
|
||||
nd->nd_symb = IDENT;
|
||||
|
||||
if (!( ChkVariable(nd) &
|
||||
ChkExpression(left->nd_left) &
|
||||
ChkExpression(left->nd_right))) return 0;
|
||||
|
||||
df = nd->nd_def;
|
||||
if (df->df_kind == D_FIELD) {
|
||||
node_error(nd,
|
||||
"FOR-loop variable may not be a field of a record");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!df->var_name && df->var_off >= 0) {
|
||||
node_error(nd, "FOR-loop variable may not be a parameter");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (df->df_scope != CurrentScope) {
|
||||
register struct scopelist *sc = CurrVis;
|
||||
|
||||
for (;;) {
|
||||
if (!sc) {
|
||||
node_error(nd,
|
||||
"FOR-loop variable may not be imported");
|
||||
return 1;
|
||||
}
|
||||
if (sc->sc_scope == df->df_scope) break;
|
||||
sc = nextvisible(sc);
|
||||
}
|
||||
}
|
||||
|
||||
if (df->df_type->tp_size > word_size ||
|
||||
!(df->df_type->tp_fund & T_DISCRETE)) {
|
||||
node_error(nd, "illegal type of FOR loop variable");
|
||||
return 1;
|
||||
}
|
||||
|
||||
tpl = left->nd_left->nd_type;
|
||||
tpr = left->nd_right->nd_type;
|
||||
if (!ChkAssCompat(&(left->nd_left), df->df_type, "FOR statement") ||
|
||||
!ChkAssCompat(&(left->nd_right), df->df_type,"FOR statement")) {
|
||||
return 1;
|
||||
}
|
||||
if (!TstCompat(df->df_type, tpl) ||
|
||||
!TstCompat(df->df_type, tpr)) {
|
||||
node_warning(nd, W_OLDFASHIONED, "compatibility required in FOR statement");
|
||||
}
|
||||
|
||||
CodePExpr(left->nd_left);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DoAssign(left, right)
|
||||
register struct node *left;
|
||||
struct node *right;
|
||||
{
|
||||
/* May we do it in this order (expression first) ???
|
||||
The reference manual sais nothing about it, but the book does:
|
||||
it sais that the left hand side is evaluated first.
|
||||
DAMN THE BOOK!
|
||||
*/
|
||||
register struct desig *dsr;
|
||||
register struct type *tp;
|
||||
|
||||
if (! (ChkExpression(right) & ChkVariable(left))) return;
|
||||
tp = left->nd_type;
|
||||
|
||||
if (right->nd_symb == STRING) TryToString(right, tp);
|
||||
|
||||
if (! ChkAssCompat(&right, tp, "assignment")) {
|
||||
return;
|
||||
}
|
||||
dsr = new_desig();
|
||||
|
||||
#define StackNeededFor(ds) ((ds)->dsg_kind == DSG_PLOADED \
|
||||
|| (ds)->dsg_kind == DSG_INDEXED)
|
||||
CodeExpr(right, dsr, NO_LABEL, NO_LABEL);
|
||||
tp = right->nd_type;
|
||||
if (complex(tp)) {
|
||||
if (StackNeededFor(dsr)) CodeAddress(dsr);
|
||||
}
|
||||
else {
|
||||
CodeValue(dsr, tp);
|
||||
}
|
||||
CodeMove(dsr, left, tp);
|
||||
free_desig(dsr);
|
||||
}
|
||||
|
||||
RegisterMessages(df)
|
||||
register struct def *df;
|
||||
{
|
||||
register struct type *tp;
|
||||
|
||||
for (; df; df = df->df_nextinscope) {
|
||||
if (df->df_kind == D_VARIABLE && !(df->df_flags & D_NOREG)) {
|
||||
/* Examine type and size
|
||||
*/
|
||||
tp = BaseType(df->df_type);
|
||||
if ((df->df_flags & D_VARPAR) ||
|
||||
(tp->tp_fund & (T_POINTER|T_HIDDEN|T_EQUAL))) {
|
||||
C_ms_reg(df->var_off, pointer_size,
|
||||
reg_pointer, 0);
|
||||
}
|
||||
else if (tp->tp_fund & T_NUMERIC) {
|
||||
C_ms_reg(df->var_off,
|
||||
tp->tp_size,
|
||||
tp->tp_fund == T_REAL ?
|
||||
reg_float : reg_any,
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
lang/m2/comp/walk.h
Normal file
20
lang/m2/comp/walk.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* P A R S E T R E E W A L K E R */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* Definition of WalkNode macro
|
||||
*/
|
||||
|
||||
extern int (*WalkTable[])();
|
||||
|
||||
#define WalkNode(xnd, xlab) (*WalkTable[(xnd)->nd_class])((xnd), (xlab))
|
||||
|
||||
extern label text_label;
|
||||
extern label data_label;
|
||||
29
lang/m2/comp/warning.h
Normal file
29
lang/m2/comp/warning.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* W A R N I N G C L A S S E S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* Warning classes, at the moment three of them:
|
||||
Strict (R)
|
||||
Ordinary (W)
|
||||
Old-fashioned(O)
|
||||
*/
|
||||
|
||||
/* Bits for a bit mask: */
|
||||
|
||||
#define W_ORDINARY 1
|
||||
#define W_STRICT 2
|
||||
#define W_OLDFASHIONED 4
|
||||
|
||||
#define W_ALL (W_ORDINARY|W_STRICT|W_OLDFASHIONED)
|
||||
|
||||
#define W_INITIAL (W_ORDINARY | W_OLDFASHIONED)
|
||||
|
||||
/* The bit mask itself: */
|
||||
extern int warning_classes;
|
||||
Reference in New Issue
Block a user