home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
379a.lha
/
p2c1_13a
/
src
/
src.zoo
/
decl3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-10
|
27KB
|
1,082 lines
/* "p2c", a Pascal to C translator.
Copyright (C) 1989 David Gillespie.
Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#define PROTO_DECL3_C
#include "trans.h"
#define MAXIMPORTS 100
extern struct ptrdesc {
struct ptrdesc *next;
Symbol *sym;
Type *tp;
} *ptrbase;
extern struct ctxstack {
struct ctxstack *next;
Meaning *ctx, *ctxlast;
struct tempvarlist *tempvars;
int tempvarcount, importmark;
} *ctxtop;
extern struct tempvarlist {
struct tempvarlist *next;
Meaning *tvar;
int active;
} *tempvars, *stmttempvars;
extern int tempvarcount;
extern int stringtypecachesize;
extern Type **stringtypecache;
extern Meaning *importlist[MAXIMPORTS];
extern int firstimport;
extern Type *tp_special_anyptr;
extern int wasaliased;
extern int deferallptrs;
extern int anydeferredptrs;
extern int silentalreadydef;
extern int nonloclabelcount;
extern Strlist *varstructdecllist;
void outbasetype(type, flags)
Type *type;
int flags;
{
Meaning *mp;
int saveindent;
type = findbasetype(type, flags);
switch (type->kind) {
case TK_INTEGER:
if (type == tp_uint) {
output("unsigned");
} else if (type == tp_sint) {
if (useAnyptrMacros == 1)
output("Signed int");
else if (hassignedchar)
output("signed int");
else
output("int"); /* will sign-extend by hand */
} else if (type == tp_unsigned) {
output("unsigned long");
} else if (type != tp_int)
output(integername);
else
output("int");
break;
case TK_SUBR:
if (type == tp_special_anyptr) {
output("Anyptr");
} else if (type == tp_abyte) {
output("char");
} else if (type == tp_ubyte) {
output(ucharname);
} else if (type == tp_sbyte) {
output(scharname);
if (signedchars != 1 && !hassignedchar)
note("'signed char' may not be valid in all compilers [102]");
} else {
if (type == tp_ushort)
output("unsigned ");
output("short");
}
break;
case TK_CHAR:
if (type == tp_uchar) {
output(ucharname);
} else if (type == tp_schar) {
output(scharname);
if (signedchars != 1 && !hassignedchar)
note("'signed char' may not be valid in all compilers [102]");
} else
output(charname);
break;
case TK_BOOLEAN:
output((*name_BOOLEAN) ? name_BOOLEAN : ucharname);
break;
case TK_REAL:
if (type == tp_longreal)
output("double");
else
output("float");
break;
case TK_VOID:
if (ansiC == 0)
output("int");
else if (useAnyptrMacros == 1)
output("Void");
else
output("void");
break;
case TK_PROCPTR:
output(name_PROCEDURE);
break;
case TK_FILE:
output("FILE");
break;
case TK_SPECIAL:
if (type == tp_jmp_buf)
output("jmp_buf");
break;
default:
if (type->meaning && type->meaning->kind == MK_TYPE &&
type->meaning->wasdeclared) {
output(type->meaning->name);
} else {
switch (type->kind) {
case TK_ENUM:
output("enum {\n");
saveindent = outindent;
moreindent(tabsize);
moreindent(structindent);
mp = type->fbase;
while (mp) {
output(mp->name);
mp = mp->xnext;
if (mp)
output(",\001 ");
}
outindent = saveindent;
output("\n}");
break;
case TK_RECORD:
if (record_is_union(type))
output("union ");
else
output("struct ");
if (type->meaning)
output(format_s(name_STRUCT, type->meaning->name));
if (!type->structdefd) {
if (type->meaning) {
type->structdefd = 1;
output(" ");
}
output("{\n");
saveindent = outindent;
moreindent(tabsize);
moreindent(structindent);
outfieldlist(type->fbase);
outindent = saveindent;
output("}");
}
break;
default:
break;
}
}
break;
}
}
void out_type(type, witharrays)
Type *type;
int witharrays;
{
if (!witharrays && type->kind == TK_ARRAY)
type = makepointertype(type->basetype);
outbasetype(type, 0);
outdeclarator(type, "", 0); /* write an "abstract declarator" */
}
int varstorageclass(mp)
Meaning *mp;
{
int sclass;
if (mp->kind == MK_PARAM || mp->kind == MK_VARPARAM ||
mp->kind == MK_FIELD)
sclass = 0;
else if (blockkind == TOK_EXPORT)
if (usevextern)
if (mp->constdefn &&
(mp->kind == MK_VAR ||
mp->kind == MK_VARREF))
sclass = 2; /* extern */
else
sclass = 1; /* vextern */
else
sclass = 0; /* (plain) */
else if (mp->isfunction && mp->kind != MK_FUNCTION)
sclass = 2; /* extern */
else if (mp->ctx->kind == MK_MODULE &&
(var_static != 0 ||
(findsymbol(mp->name)->flags & NEEDSTATIC)) &&
!mp->exported && !mp->istemporary && blockkind != TOK_END)
sclass = (useAnyptrMacros) ? 4 : 3; /* (private) */
else if (mp->isforward)
sclass = 3; /* static */
else
sclass = 0; /* (plain) */
if (mp->volatilequal)
sclass |= 0x10;
if (mp->constqual)
sclass |= 0x20;
if (debug>2) fprintf(outf, "varstorageclass(%s) = %d\n", mp->name, sclass);
return sclass;
}
char *storageclassname(i)
int i;
{
char *scname;
switch (i & 0xf) {
case 1:
scname = "vextern ";
break;
case 2:
scname = "extern ";
break;
case 3:
scname = "static ";
break;
case 4:
scname = "Static ";
break;
default:
scname = "";
break;
}
if (i & 0x10)
if (useAnyptrMacros == 1)
scname = format_s("%sVolatile ", scname);
else if (ansiC > 0)
scname = format_s("%svolatile ", scname);
if (i & 0x20)
if (useAnyptrMacros == 1)
scname = format_s("%sConst ", scname);
else if (ansiC > 0)
scname = format_s("%sconst ", scname);
return scname;
}
void declarevar(mp, which)
Meaning *mp;
int which; /* 0x1=header, 0x2=body, 0x4=trailer, 0x8=in varstruct */
{
int isstatic, isstructconst, saveindent;
isstructconst = checkstructconst(mp);
isstatic = varstorageclass(mp);
if (which & 0x8)
isstatic &= 0x10; /* clear all but Volatile flags */
flushcomments(&mp->comments, CMT_PRE, -1);
if (which & 0x1) {
if (isstructconst)
outsection(minorspace);
output(storageclassname(isstatic));
outbasetype(mp->type, 0);
output(" \005");
}
if (which & 0x2) {
outdeclarator(mp->type, mp->name, 0);
if (mp->constdefn && blockkind != TOK_EXPORT &&
(mp->kind == MK_VAR || mp->kind == MK_VARREF)) {
if (mp->varstructflag) { /* move init code into function body */
intwarning("declarevar",
format_s("Variable %s initializer not removed [125]", mp->name));
} else {
output(" = ");
if (isstructconst) {
output("{\n");
saveindent = outindent;
moreindent(tabsize);
moreindent(structinitindent);
out_expr((Expr *)mp->constdefn->val.i);
outindent = saveindent;
output("\n}");
} else
out_expr(mp->constdefn);
}
}
}
if (which & 0x4) {
output(";");
outtrailcomment(mp->comments, -1, declcommentindent);
flushcomments(&mp->comments, -1, -1);
if (isstructconst)
outsection(minorspace);
}
}
Static int checkvarmacdef(ex, mp)
Expr *ex;
Meaning *mp;
{
int i;
if ((ex->kind == EK_NAME || ex->kind == EK_BICALL) &&
!strcmp(ex->val.s, mp->name)) {
ex->kind = EK_VAR;
ex->val.i = (long)mp;
ex->val.type = mp->type;
return 1;
}
if (ex->kind == EK_VAR && ex->val.i == (long)mp)
return 1;
i = ex->nargs;
while (--i >= 0)
if (checkvarmacdef(ex->args[i], mp))
return 1;
return 0;
}
int checkvarmac(mp)
Meaning *mp;
{
if (mp->kind != MK_VARMAC && mp->kind != MK_FUNCTION)
return 0;
if (!mp->constdefn)
return 0;
return checkvarmacdef(mp->constdefn, mp);
}
#define varkind(k) ((k)==MK_VAR||(k)==MK_VARREF||(k)==MK_PARAM||(k)==MK_VARPARAM)
int declarevars(ctx, invarstruct)
Meaning *ctx;
int invarstruct;
{
Meaning *mp, *mp0, *mp2;
Strlist *fnames, *fn;
int flag, first;
if (ctx->kind == MK_FUNCTION && ctx->varstructflag && !invarstruct) {
output("struct ");
output(format_s(name_LOC, ctx->name));
output(" ");
output(format_s(name_VARS, ctx->name));
output(";\n");
flag = 1;
} else
flag = 0;
if (debug>2) {
fprintf(outf,"declarevars:\n");
for (mp = ctx->cbase; mp; mp = mp->xnext) {
fprintf(outf, " %-22s%-15s%3d", mp->name,
meaningkindname(mp->kind),
mp->refcount);
if (mp->wasdeclared)
fprintf(outf, " [decl]");
if (mp->varstructflag)
fprintf(outf, " [struct]");
fprintf(outf, "\n");
}
}
fnames = NULL;
for (;;) {
mp = ctx->cbase;
while (mp && (!(varkind(mp->kind) || checkvarmac(mp)) ||
mp->wasdeclared || mp->varstructflag != invarstruct ||
mp->refcount <= 0))
mp = mp->cnext;
if (!mp)
break;
flag = 1;
first = 1;
mp0 = mp2 = mp;
while (mp) {
if ((varkind(mp->kind) || checkvarmac(mp)) &&
!mp->wasdeclared &&
varstorageclass(mp) == varstorageclass(mp0) &&
mp->varstructflag == invarstruct && mp->refcount > 0) {
if (mixable(mp2, mp, 0, 0) || first) {
if (!first)
output(",\001 ");
declarevar(mp, (first ? 0x3 : 0x2) |
(invarstruct ? 0x8 : 0));
mp2 = mp;
mp->wasdeclared = 1;
if (isfiletype(mp->type)) {
fn = strlist_append(&fnames, mp->name);
fn->value = (long)mp;
}
first = 0;
} else
if (mixvars != 1)
break;
}
if (first) {
intwarning("declarevars",
format_s("Unable to declare %s [126]", mp->name));
mp->wasdeclared = 1;
first = 0;
}
if (mixvars == 0)
break;
mp = mp->cnext;
}
declarevar(mp2, 0x4);
}
declarefiles(fnames);
return flag;
}
void redeclarevars(ctx)
Meaning *ctx;
{
Meaning *mp;
for (mp = ctx->cbase; mp; mp = mp->cnext) {
if ((mp->kind == MK_VAR || mp->kind == MK_VARREF) &&
mp->constdefn) {
mp->wasdeclared = 0; /* mark for redeclaration, this time */
} /* with its initializer */
}
}
void out_argdecls(ftype)
Type *ftype;
{
Meaning *mp, *mp0;
Type *tp;
int done;
int flag = 1;
char *name;
done = 0;
do {
mp = ftype->fbase;
while (mp && mp->wasdeclared)
mp = mp->xnext;
if (mp) {
if (flag)
output("\n");
flag = 0;
mp0 = mp;
outbasetype(mp->othername ? mp->rectype : mp->type,
ODECL_CHARSTAR|ODECL_FREEARRAY);
output(" \005");
while (mp) {
if (!mp->wasdeclared) {
if (mp == mp0 ||
mixable(mp0, mp, 1, ODECL_CHARSTAR|ODECL_FREEARRAY)) {
if (mp != mp0)
output(",\001 ");
name = (mp->othername) ? mp->othername : mp->name;
tp = (mp->othername) ? mp->rectype : mp->type;
outdeclarator(tp, name,
ODECL_CHARSTAR|ODECL_FREEARRAY);
mp->wasdeclared = 1;
} else
if (mixvars != 1)
break;
}
mp = mp->xnext;
}
output(";\n");
} else
done = 1;
} while (!done);
for (mp0 = ftype->fbase; mp0 && (mp0->type != tp_strptr ||
!mp0->anyvarflag); mp0 = mp0->xnext) ;
if (mp0) {
output("int ");
for (mp = mp0; mp; mp = mp->xnext) {
if (mp->type == tp_strptr && mp->anyvarflag) {
if (mp != mp0) {
if (mixvars == 0)
output(";\nint ");
else
output(",\001 ");
}
output(format_s(name_STRMAX, mp->name));
}
}
output(";\n");
}
if (ftype->meaning && ftype->meaning->ctx->kind == MK_FUNCTION &&
ftype->meaning->ctx->varstructflag) {
if (flag)
output("\n");
output("struct ");
output(format_s(name_LOC, ftype->meaning->ctx->name));
output(" *");
output(format_s(name_LINK, ftype->meaning->ctx->name));
output(";\n");
}
}
void makevarstruct(func)
Meaning *func;
{
int flag = 0;
int saveindent;
outsection(minfuncspace);
output(format_s("\n/* Local variables for %s: */\n", func->name));
output("struct ");
output(format_s(name_LOC, func->name));
output(" {\n");
saveindent = outindent;
moreindent(tabsize);
moreindent(structindent);
if (func->ctx->kind == MK_FUNCTION && func->ctx->varstructflag) {
output("struct ");
output(format_s(name_LOC, func->ctx->name));
output(" *");
output(format_s(name_LINK, func->ctx->name));
output(";\n");
flag++;
}
flag += declarevars(func, 1);
if (!flag) /* Avoid generating an empty struct */
output("int _meef_;\n"); /* (I don't think this will ever happen) */
outindent = saveindent;
output("} ;\n");
outsection(minfuncspace);
strlist_insert(&varstructdecllist, func->name);
}
Type *maketype(kind)
enum typekind kind;
{
Type *tp;
tp = ALLOC(1, Type, types);
tp->kind = kind;
tp->basetype = NULL;
tp->indextype = NULL;
tp->pointertype = NULL;
tp->meaning = NULL;
tp->fbase = NULL;
tp->smin = NULL;
tp->smax = NULL;
tp->issigned = 0;
tp->dumped = 0;
tp->structdefd = 0;
return tp;
}
Type *makesubrangetype(type, smin, smax)
Type *type;
Expr *smin, *smax;
{
Type *tp;
if (type->kind == TK_SUBR)
type = type->basetype;
tp = maketype(TK_SUBR);
tp->basetype = type;
tp->smin = smin;
tp->smax = smax;
return tp;
}
Type *makesettype(setof)
Type *setof;
{
Type *tp;
long smax;
if (ord_range(setof, NULL, &smax) && smax < setbits && smallsetconst >= 0)
tp = maketype(TK_SMALLSET);
else
tp = maketype(TK_SET);
tp->basetype = tp_integer;
tp->indextype = setof;
return tp;
}
Type *makestringtype(len)
int len;
{
Type *type;
int index;
len |= 1;
if (len >= stringceiling)
type = tp_str255;
else {
index = (len-1) / 2;
if (stringtypecache[index])
return stringtypecache[index];
type = maketype(TK_STRING);
type->basetype = tp_char;
type->indextype = makesubrangetype(tp_integer,
makeexpr_long(0),
makeexpr_long(len));
stringtypecache[index] = type;
}
return type;
}
Type *makepointertype(type)
Type *type;
{
Type *tp;
if (type->pointertype)
return type->pointertype;
tp = maketype(TK_POINTER);
tp->basetype = type;
type->pointertype = tp;
return tp;
}
Value p_constant(type)
Type *type;
{
Value val;
Expr *ex;
ex = p_expr(type);
if (type)
ex = gentle_cast(ex, type);
val = eval_expr(ex);
freeexpr(ex);
if (!val.type) {
warning("Expected a constant [127]");
val.type = (type) ? type : tp_integer;
}
return val;
}
int typebits(smin, smax)
long smin, smax;
{
unsigned long size;
int bits;
if (smin >= 0 || (smin == -1 && smax == 0)) {
bits = 1;
size = smax;
} else {
bits = 2;
smin = -1L - smin;
if (smin >= smax)
size = smin;
else
size = smax;
}
while (size > 1) {
bits++;
size >>= 1;
}
return bits;
}
int packedsize(fname, typep, sizep, mode)
char *fname;
Type **typep;
long *sizep;
int mode;
{
Type *tp = *typep;
long smin, smax;
int res, issigned;
short savefold;
long size;
if (packing == 0) /* suppress packing */
return 0;
if (tp->kind != TK_SUBR && tp->kind != TK_INTEGER && tp->kind != TK_ENUM &&
tp->kind != TK_CHAR && tp->kind != TK_BOOLEAN)
return 0;
if (tp == tp_unsigned)
return 0;
if (!ord_range(tp, &smin, &smax)) {
savefold = foldconsts;
foldconsts = 1;
res = ord_range(tp, &smin, &smax);
foldconsts = savefold;
if (res) {
note(format_s("Field width for %s is based on expansion of #defines [103]",
fname));
} else {
note(format_ss("Cannot compute size of field %s; assuming %s [104]",
fname, integername));
return 0;
}
} else {
if (tp->kind == TK_ENUM)
note(format_ssd("Field width for %s assumes enum%s has %d elements [105]",
fname,
(tp->meaning) ? format_s(" %s", tp->meaning->name) : "",
smax + 1));
}
issigned = (smin < 0);
size = typebits(smin, smax);
if (size >= ((sizeof_long > 0) ? sizeof_long : 32))
return 0;
if (packing != 1) {
if (size <= 8)
size = 8;
else if (size <= 16)
size = 16;
else
return 0;
}
if (!issigned) {
*typep = (mode == 0) ? tp_int : tp_uint;
} else {
if (mode == 2 && !hassignedchar && !*signextname)
return 0;
*typep = (mode == 1) ? tp_int : tp_sint;
}
*sizep = size;
return issigned;
}
Static void fielddecl(mp, type, tp2, val, ispacked, aligned)
Meaning *mp;
Type **type, **tp2;
long *val;
int ispacked, *aligned;
{
long smin, smax, smin2, smax2;
*tp2 = *type;
*val = 0;
if (ispacked && !mp->constdefn && *type != tp_unsigned) {
(void)packedsize(mp->sym->name, tp2, val, signedfield);
if (*aligned && *val &&
(ord_type(*type)->kind == TK_CHAR ||
ord_type(*type)->kind == TK_INTEGER) &&
ord_range(findbasetype(*type, 0), &smin, &smax)) {
if (ord_range(*type, &smin2, &smax2)) {
if (typebits(smin, smax) == 16 &&
typebits(smin2, smax2) == 8 && *val == 8) {
*tp2 = tp_abyte;
}
}
if (typebits(smin, smax) == *val &&
*val != 7) { /* don't be fooled by tp_abyte */
/* don't need to use a bit-field for this field */
/* so not specifying one may make it more efficient */
/* (and also helps to simulate HP's $allow_packed$ mode) */
*val = 0;
*tp2 = *type;
}
}
if (*aligned && *val == 8 &&
(ord_type(*type)->kind == TK_BOOLEAN ||
ord_type(*type)->kind == TK_ENUM)) {
*val = 0;
*tp2 = tp_ubyte;
}
}
if (*val != 8 && *val != 16)
*aligned = (*val == 0);
}
/* This function locates byte-sized fields which were unaligned, but which
are followed by aligned quantities so that they can be made aligned
with no loss in storage efficiency. */
Static void realignfields(firstmp, stopmp)
Meaning *firstmp, *stopmp;
{
Meaning *mp;
for (mp = firstmp; mp && mp != stopmp; mp = mp->cnext) {
if (mp->kind == MK_FIELD) {
if (mp->val.i == 16) {
if (mp->type == tp_uint)
mp->type = tp_ushort;
else
mp->type = tp_sshort;
mp->val.i = 0;
} else if (mp->val.i == 8) {
if (mp->type == tp_uint) {
mp->type = tp_ubyte;
mp->val.i = 0;
} else if (hassignedchar || signedchars == 1) {
mp->type = tp_sbyte;
mp->val.i = 0;
} else
mp->type = tp_abyte;
}
}
}
}
static void tryrealignfields(firstmp)
Meaning *firstmp;
{
Meaning *mp, *head;
head = NULL;
for (mp = firstmp; mp; mp = mp->cnext) {
if (mp->kind == MK_FIELD) {
if (mp->val.i == 8 || mp->val.i == 16) {
if (!head)
head = mp;
} else {
if (mp->val.i == 0)
realignfields(head, mp);
head = NULL;
}
}
}
realignfields(head, NULL);
}
void decl_comments(mp)
Meaning *mp;
{
Strlist *cmt;
if (spitcomments != 1) {
changecomments(curcomments, -1, -1, CMT_PRE, 0);
strlist_mix(&mp->comments, curcomments);
curcomments = NULL;
cmt = grabcomment(CMT_TRAIL);
if (cmt) {
changecomments(mp->comments, CMT_TRAIL, -1, CMT_PRE, -1);
strlist_mix(&mp->comments, cmt);
}
if (mp->comments)
mp->refcount++; /* force it to be included if it has comments */
}
}
Static void p_fieldlist(tp, flast, ispacked, tname)
Type *tp;
Meaning **flast;
int ispacked;
Meaning *tname;
{
Meaning *firstm, *lastm, *veryfirstm;
Symbol *sym;
Type *type, *tp2;
long li1, li2;
int aligned, constflag, volatileflag;
short saveskipind;
Strlist *l1;
saveskipind = skipindices;
skipindices = 0;
aligned = 1;
lastm = NULL;
veryfirstm = NULL;
while (curtok == TOK_IDENT) {
firstm = addfield(curtoksym, &flast, tp, tname);
if (!veryfirstm)
veryfirstm = firstm;
lastm = firstm;
gettok();
decl_comments(lastm);
while (curtok == TOK_COMMA) {
gettok();
if (wexpecttok(TOK_IDENT))
lastm = addfield(curtoksym, &flast, tp, tname);
gettok();
decl_comments(lastm);
}
if (wneedtok(TOK_COLON)) {
constflag = volatileflag = 0;
p_attributes();
if ((l1 = strlist_find(attrlist, "READONLY")) != NULL) {
constflag = 1;
strlist_delete(&attrlist, l1);
}
if ((l1 = strlist_find(attrlist, "VOLATILE")) != NULL) {
volatileflag = 1;
strlist_delete(&attrlist, l1);
}
type = p_type(firstm);
decl_comments(lastm);
fielddecl(firstm, &type, &tp2, &li1, ispacked, &aligned);
for (;;) {
firstm->type = tp2;
firstm->val.type = type;
firstm->val.i = li1;
firstm->constqual = constflag;
firstm->volatilequal = volatileflag;
tp->meaning = tname;
setupfilevar(firstm);
tp->meaning = NULL;
if (firstm == lastm)
break;
firstm = firstm->cnext;
}
} else
skiptotoken2(TOK_SEMI, TOK_CASE);
if (curtok == TOK_SEMI)
gettok();
}
if (curtok == TOK_CASE) {
gettok();
if (curtok == TOK_COLON)
gettok();
wexpecttok(TOK_IDENT);
sym = curtoksym;
if (curtokmeaning)
type = curtokmeaning->type;
gettok();
if (curtok == TOK_COLON) {
firstm = addfield(sym, &flast, tp, tname);
if (!veryfirstm)
veryfirstm = firstm;
gettok();
firstm->isforward = 1;
firstm->val.type = type = p_type(firstm);
fielddecl(firstm, &firstm->val.type, &firstm->type, &firstm->val.i,
ispacked, &aligned);
} else {
firstm = NULL;
}
if (!wneedtok(TOK_OF)) {
skiptotoken2(TOK_END, TOK_RPAR);
goto bounce;
}
if (firstm)
decl_comments(firstm);
while (curtok == TOK_VBAR)
gettok();
while (curtok != TOK_END && curtok != TOK_RPAR) {
firstm = NULL;
for (;;) {
lastm = addfield(NULL, &flast, tp, tname);
if (!firstm)
firstm = lastm;
checkkeyword(TOK_OTHERWISE);
if (curtok == TOK_ELSE || curtok == TOK_OTHERWISE) {
lastm->val = make_ord(type, 999);
break;
} else {
lastm->val = p_constant(type);
if (curtok == TOK_DOTS) {
gettok();
li1 = ord_value(lastm->val);
li2 = ord_value(p_constant(type));
while (++li1 <= li2) {
lastm = addfield(NULL, &flast, tp, tname);
lastm->val = make_ord(type, li1);
}
}
}
if (curtok == TOK_COMMA)
gettok();
else
break;
}
if (curtok == TOK_ELSE || curtok == TOK_OTHERWISE) {
gettok();
} else if (!wneedtok(TOK_COLON) ||
(!modula2 && !wneedtok(TOK_LPAR))) {
skiptotoken2(TOK_END, TOK_RPAR);
goto bounce;
}
p_fieldlist(tp, &lastm->ctx, ispacked, tname);
while (firstm != lastm) {
firstm->ctx = lastm->ctx;
firstm = firstm->cnext;
}
if (modula2) {
while (curtok == TOK_VBAR)
gettok();
} else {
if (!wneedtok(TOK_RPAR))
skiptotoken(TOK_RPAR);
}
if (curtok == TOK_SEMI)
gettok();
}
if (modula2) {
wneedtok(TOK_END);
if (curtok == TOK_IDENT) {
note("Record variants supported only at end of record [106]");
p_fieldlist(tp, &lastm->ctx, ispacked, tname);
}
}
}
tryrealignfields(veryfirstm);
if (lastm && curtok == TOK_END) {
strlist_mix(&lastm->comments, curcomments);
curcomments = NULL;
}
bounce:
skipindices = saveskipind;
}