ack/lang/m2/comp/declar.g

547 lines
11 KiB
Plaintext
Raw Normal View History

1986-03-26 15:11:02 +00:00
/* D E C L A R A T I O N S */
1986-03-20 14:52:03 +00:00
1986-03-26 15:11:02 +00:00
{
1986-05-01 19:06:53 +00:00
#include "debug.h"
1986-03-20 14:52:03 +00:00
1986-03-26 15:11:02 +00:00
#include <em_arith.h>
#include <em_label.h>
1986-04-08 18:15:46 +00:00
#include <alloc.h>
1986-03-26 22:46:48 +00:00
#include <assert.h>
1986-04-22 22:36:16 +00:00
1986-03-26 15:11:02 +00:00
#include "idf.h"
#include "LLlex.h"
#include "def.h"
#include "type.h"
#include "scope.h"
1986-04-06 17:42:56 +00:00
#include "node.h"
#include "misc.h"
1986-04-18 17:53:47 +00:00
#include "main.h"
1986-06-26 09:39:36 +00:00
#include "chk_expr.h"
1986-11-05 14:33:00 +00:00
#include "warning.h"
1986-04-15 17:51:53 +00:00
1986-06-20 14:36:49 +00:00
int proclevel = 0; /* nesting level of procedures */
1986-10-06 20:36:30 +00:00
int return_occurred; /* set if a return occurs in a block */
1986-03-26 15:11:02 +00:00
}
1986-03-20 14:52:03 +00:00
1986-03-26 15:11:02 +00:00
ProcedureDeclaration
{
1986-10-06 20:36:30 +00:00
struct def *df;
1986-03-26 15:11:02 +00:00
} :
1986-10-06 20:36:30 +00:00
{ ++proclevel; }
ProcedureHeading(&df, D_PROCEDURE)
';' block(&(df->prc_body))
IDENT
{ EndProc(df, dot.TOK_IDF);
1986-07-08 14:59:02 +00:00
--proclevel;
1986-03-26 15:11:02 +00:00
}
;
1986-03-26 22:46:48 +00:00
ProcedureHeading(struct def **pdf; int type;)
1986-03-26 15:11:02 +00:00
{
1986-10-06 20:36:30 +00:00
struct type *tp = 0;
#define needs_static_link() (proclevel > 1)
arith parmaddr = needs_static_link() ? pointer_size : 0;
struct paramlist *pr = 0;
1986-03-26 15:11:02 +00:00
} :
PROCEDURE IDENT
1986-10-06 20:36:30 +00:00
{ *pdf = DeclProc(type, dot.TOK_IDF); }
FormalParameters(&pr, &parmaddr, &tp)?
1986-12-09 17:41:06 +00:00
{ 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);
}
}
1986-03-20 14:52:03 +00:00
;
1986-06-26 09:39:36 +00:00
block(struct node **pnd;) :
[ %persistent
declaration
]*
{ return_occurred = 0; *pnd = 0; }
[ %persistent
1986-04-17 09:28:09 +00:00
BEGIN
StatementSequence(pnd)
]?
1986-04-17 09:28:09 +00:00
END
1986-03-20 14:52:03 +00:00
;
declaration:
CONST [ %persistent ConstantDeclaration ';' ]*
1986-03-20 14:52:03 +00:00
|
TYPE [ %persistent TypeDeclaration ';' ]*
1986-03-20 14:52:03 +00:00
|
VAR [ %persistent VariableDeclaration ';' ]*
1986-03-20 14:52:03 +00:00
|
ProcedureDeclaration ';'
|
ModuleDeclaration ';'
;
FormalParameters(struct paramlist **ppr; arith *parmaddr; struct type **ptp;):
1986-03-27 17:37:41 +00:00
'('
[
1986-10-06 20:36:30 +00:00
FPSection(ppr, parmaddr)
1986-03-27 17:37:41 +00:00
[
1986-10-06 20:36:30 +00:00
';' FPSection(ppr, parmaddr)
1986-03-27 17:37:41 +00:00
]*
]?
')'
1986-07-08 14:59:02 +00:00
[ ':' qualtype(ptp)
1986-03-26 15:11:02 +00:00
]?
1986-03-20 14:52:03 +00:00
;
1986-05-30 18:48:00 +00:00
FPSection(struct paramlist **ppr; arith *parmaddr;)
1986-03-20 14:52:03 +00:00
{
1986-04-06 17:42:56 +00:00
struct node *FPList;
1986-03-29 01:04:49 +00:00
struct type *tp;
1986-07-08 14:59:02 +00:00
int VARp;
1986-03-20 14:52:03 +00:00
} :
1986-08-26 14:33:24 +00:00
var(&VARp) IdentList(&FPList) ':' FormalType(&tp)
{ EnterParamList(ppr, FPList, tp, VARp, parmaddr); }
1986-03-20 14:52:03 +00:00
;
1986-08-26 14:33:24 +00:00
FormalType(struct type **ptp;)
1986-03-27 17:37:41 +00:00
{
1986-06-04 09:01:48 +00:00
extern arith ArrayElSize();
1986-03-27 17:37:41 +00:00
} :
1986-08-26 14:33:24 +00:00
ARRAY OF qualtype(ptp)
1986-10-06 20:36:30 +00:00
{ register struct type *tp = construct_type(T_ARRAY, NULLTYPE);
1986-11-26 16:40:45 +00:00
1986-10-06 20:36:30 +00:00
tp->arr_elem = *ptp;
*ptp = tp;
1986-08-26 14:33:24 +00:00
tp->arr_elsize = ArrayElSize(tp->arr_elem);
1986-11-26 16:40:45 +00:00
tp->tp_align = tp->arr_elem->tp_align;
1986-04-21 17:27:06 +00:00
}
1986-08-26 14:33:24 +00:00
|
qualtype(ptp)
1986-03-20 14:52:03 +00:00
;
1986-03-26 15:11:02 +00:00
TypeDeclaration
{
1986-08-26 14:33:24 +00:00
struct def *df;
1986-03-27 17:37:41 +00:00
struct type *tp;
1986-12-01 10:06:53 +00:00
struct node *nd;
1986-03-26 15:11:02 +00:00
}:
1986-12-01 10:06:53 +00:00
IDENT { df = define(dot.TOK_IDF, CurrentScope, D_TYPE);
nd = MkLeaf(Name, &dot);
}
1986-03-27 17:37:41 +00:00
'=' type(&tp)
1986-12-01 10:06:53 +00:00
{ DeclareType(nd, df, tp);
free_node(nd);
}
1986-03-20 14:52:03 +00:00
;
1986-03-27 17:37:41 +00:00
type(struct type **ptp;):
1986-08-26 14:33:24 +00:00
%default SimpleType(ptp)
1986-03-20 14:52:03 +00:00
|
1986-03-27 17:37:41 +00:00
ArrayType(ptp)
1986-03-20 14:52:03 +00:00
|
1986-03-27 17:37:41 +00:00
RecordType(ptp)
1986-03-20 14:52:03 +00:00
|
1986-03-27 17:37:41 +00:00
SetType(ptp)
1986-03-20 14:52:03 +00:00
|
1986-03-27 17:37:41 +00:00
PointerType(ptp)
1986-03-20 14:52:03 +00:00
|
1986-03-27 17:37:41 +00:00
ProcedureType(ptp)
1986-03-20 14:52:03 +00:00
;
1986-03-27 17:37:41 +00:00
SimpleType(struct type **ptp;)
{
1986-07-08 14:59:02 +00:00
struct type *tp;
1986-03-27 17:37:41 +00:00
} :
1986-07-08 14:59:02 +00:00
qualtype(ptp)
1986-03-20 14:52:03 +00:00
[
1986-03-29 01:04:49 +00:00
/* nothing */
1986-03-20 14:52:03 +00:00
|
1986-07-08 14:59:02 +00:00
SubrangeType(&tp)
1986-03-29 01:04:49 +00:00
/* The subrange type is given a base type by the
qualident (this is new modula-2).
*/
1986-07-08 14:59:02 +00:00
{ chk_basesubrange(tp, *ptp); }
1986-03-20 14:52:03 +00:00
]
|
1986-03-27 17:37:41 +00:00
enumeration(ptp)
1986-03-20 14:52:03 +00:00
|
1986-03-27 17:37:41 +00:00
SubrangeType(ptp)
1986-03-20 14:52:03 +00:00
;
1986-03-27 17:37:41 +00:00
enumeration(struct type **ptp;)
1986-03-20 14:52:03 +00:00
{
1986-04-06 17:42:56 +00:00
struct node *EnumList;
1986-03-20 14:52:03 +00:00
} :
'(' IdentList(&EnumList) ')'
1986-11-26 16:40:45 +00:00
{ register struct type *tp =
standard_type(T_ENUMERATION, int_align, int_size);
*ptp = tp;
EnterEnumList(EnumList, tp);
if (ufit(tp->enm_ncst-1, 1)) {
tp->tp_size = 1;
tp->tp_align = 1;
}
1986-11-26 16:40:45 +00:00
else if (ufit(tp->enm_ncst-1, short_size)) {
tp->tp_size = short_size;
tp->tp_align = short_align;
1986-04-15 17:51:53 +00:00
}
1986-04-10 01:08:49 +00:00
}
1986-03-20 14:52:03 +00:00
;
1986-04-06 17:42:56 +00:00
IdentList(struct node **p;)
1986-03-20 14:52:03 +00:00
{
1986-04-06 17:42:56 +00:00
register struct node *q;
1986-03-20 14:52:03 +00:00
} :
1986-07-08 14:59:02 +00:00
IDENT { *p = q = MkLeaf(Value, &dot); }
1986-08-26 14:33:24 +00:00
[ %persistent
1986-04-06 17:42:56 +00:00
',' IDENT
1986-06-04 09:01:48 +00:00
{ q->next = MkLeaf(Value, &dot);
1986-04-06 17:42:56 +00:00
q = q->next;
}
1986-03-20 14:52:03 +00:00
]*
1986-04-06 17:42:56 +00:00
{ q->next = 0; }
1986-03-20 14:52:03 +00:00
;
1986-03-27 17:37:41 +00:00
SubrangeType(struct type **ptp;)
{
1986-04-08 23:34:10 +00:00
struct node *nd1, *nd2;
1986-03-27 17:37:41 +00:00
}:
1986-03-20 14:52:03 +00:00
/*
This is not exactly the rule in the new report, but see
the rule for "SimpleType".
*/
1986-04-06 17:42:56 +00:00
'[' ConstExpression(&nd1)
UPTO ConstExpression(&nd2)
1986-03-27 17:37:41 +00:00
']'
1986-10-06 20:36:30 +00:00
{ *ptp = subr_type(nd1, nd2);
free_node(nd1);
free_node(nd2);
}
1986-03-20 14:52:03 +00:00
;
1986-03-27 17:37:41 +00:00
ArrayType(struct type **ptp;)
{
struct type *tp;
register struct type *tp2;
} :
ARRAY SimpleType(&tp)
1986-07-08 14:59:02 +00:00
{ *ptp = tp2 = construct_type(T_ARRAY, tp); }
1986-03-27 17:37:41 +00:00
[
',' SimpleType(&tp)
1986-05-28 18:36:51 +00:00
{ tp2->arr_elem = construct_type(T_ARRAY, tp);
tp2 = tp2->arr_elem;
1986-03-27 17:37:41 +00:00
}
]* OF type(&tp)
1986-04-15 17:51:53 +00:00
{ tp2->arr_elem = tp;
ArraySizes(*ptp);
}
1986-03-20 14:52:03 +00:00
;
1986-03-27 17:37:41 +00:00
RecordType(struct type **ptp;)
{
1986-07-08 14:59:02 +00:00
register struct scope *scope;
1986-10-22 15:38:24 +00:00
arith size = 0;
1986-04-17 09:28:09 +00:00
int xalign = struct_align;
1986-03-27 17:37:41 +00:00
}
:
RECORD
1986-10-06 20:36:30 +00:00
{ open_scope(OPENSCOPE); /* scope for fields of record */
1986-07-08 14:59:02 +00:00
scope = CurrentScope;
close_scope(0);
}
1986-10-06 20:36:30 +00:00
FieldListSequence(scope, &size, &xalign)
1986-12-01 10:06:53 +00:00
{ if (size == 0) {
warning(W_ORDINARY, "empty record declaration");
size = 1;
}
*ptp = standard_type(T_RECORD, xalign, size);
1986-04-15 17:51:53 +00:00
(*ptp)->rec_scope = scope;
1986-04-10 01:08:49 +00:00
}
1986-03-27 17:37:41 +00:00
END
1986-03-20 14:52:03 +00:00
;
1986-04-15 17:51:53 +00:00
FieldListSequence(struct scope *scope; arith *cnt; int *palign;):
FieldList(scope, cnt, palign)
1986-03-27 17:37:41 +00:00
[
1986-04-15 17:51:53 +00:00
';' FieldList(scope, cnt, palign)
1986-03-27 17:37:41 +00:00
]*
1986-03-20 14:52:03 +00:00
;
1986-04-15 17:51:53 +00:00
FieldList(struct scope *scope; arith *cnt; int *palign;)
1986-03-20 14:52:03 +00:00
{
1986-04-06 17:42:56 +00:00
struct node *FldList;
1986-10-06 20:36:30 +00:00
register struct idf *id = 0;
1986-03-27 17:37:41 +00:00
struct type *tp;
1986-10-06 20:36:30 +00:00
struct node *nd1;
register struct node *nd;
1986-04-15 17:51:53 +00:00
arith tcnt, max;
1986-03-20 14:52:03 +00:00
} :
[
1986-03-27 17:37:41 +00:00
IdentList(&FldList) ':' type(&tp)
1986-04-15 17:51:53 +00:00
{ *palign = lcm(*palign, tp->tp_align);
1986-06-10 13:18:52 +00:00
EnterFieldList(FldList, tp, scope, cnt);
1986-04-04 13:47:04 +00:00
}
1986-03-20 14:52:03 +00:00
|
1986-03-27 17:37:41 +00:00
CASE
1986-10-06 20:36:30 +00:00
/* Also accept old fashioned Modula-2 syntax, but give a warning.
Sorry for the complicated code.
1986-04-11 11:57:19 +00:00
*/
[ qualident(&nd1)
1986-10-06 20:36:30 +00:00
{ nd = nd1; }
[ ':' qualtype(&tp)
1986-07-08 14:59:02 +00:00
/* This is correct, in both kinds of Modula-2, if
1986-10-06 20:36:30 +00:00
the first qualident is a single identifier.
1986-04-11 11:57:19 +00:00
*/
1986-10-06 20:36:30 +00:00
{ if (nd->nd_class != Name) {
error("illegal variant tag");
}
else id = nd->nd_IDF;
FreeNode(nd);
}
| /* Old fashioned! the first qualident now represents
1986-04-11 11:57:19 +00:00
the type
*/
1986-11-05 14:33:00 +00:00
{ warning(W_OLDFASHIONED, "old fashioned Modula-2 syntax; ':' missing");
1986-10-06 20:36:30 +00:00
if (ChkDesignator(nd) &&
(nd->nd_class != Def ||
!(nd->nd_def->df_kind&(D_ERROR|D_ISTYPE)) ||
!nd->nd_def->df_type)) {
node_error(nd, "type expected");
tp = error_type;
}
else tp = nd->nd_def->df_type;
FreeNode(nd);
}
]
| ':' qualtype(&tp)
/* Aha, third edition. Well done! */
1986-04-11 11:57:19 +00:00
]
1986-10-06 20:36:30 +00:00
{ if (id) {
register struct def *df = define(id,
scope,
D_FIELD);
if (!(tp->tp_fund & T_DISCRETE)) {
1986-11-05 14:33:00 +00:00
error("illegal type in variant");
1986-10-06 20:36:30 +00:00
}
df->df_type = tp;
df->fld_off = align(*cnt, tp->tp_align);
1986-10-22 15:38:24 +00:00
*cnt = df->fld_off + tp->tp_size;
1986-10-06 20:36:30 +00:00
df->df_flags |= D_QEXPORTED;
}
1986-10-22 15:38:24 +00:00
tcnt = *cnt;
1986-10-06 20:36:30 +00:00
}
1986-04-15 17:51:53 +00:00
OF variant(scope, &tcnt, tp, palign)
1986-10-06 20:36:30 +00:00
{ max = tcnt; tcnt = *cnt; }
1986-03-27 17:37:41 +00:00
[
1986-10-06 20:36:30 +00:00
'|' variant(scope, &tcnt, tp, palign)
{ if (tcnt > max) max = tcnt; tcnt = *cnt; }
1986-03-27 17:37:41 +00:00
]*
1986-04-15 17:51:53 +00:00
[ ELSE FieldListSequence(scope, &tcnt, palign)
1986-10-06 20:36:30 +00:00
{ if (tcnt > max) max = tcnt; }
1986-03-27 17:37:41 +00:00
]?
1986-03-20 14:52:03 +00:00
END
1986-10-06 20:36:30 +00:00
{ *cnt = max; }
1986-03-20 14:52:03 +00:00
]?
;
1986-04-15 17:51:53 +00:00
variant(struct scope *scope; arith *cnt; struct type *tp; int *palign;)
{
1986-04-17 09:28:09 +00:00
struct node *nd;
1986-04-15 17:51:53 +00:00
} :
[
1986-10-06 20:36:30 +00:00
CaseLabelList(&tp, &nd)
{ /* Ignore the cases for the time being.
Maybe a checking version will be supplied
later ??? (Improbable)
*/
FreeNode(nd);
}
1986-04-17 09:28:09 +00:00
':' FieldListSequence(scope, cnt, palign)
1986-04-15 17:51:53 +00:00
]?
1986-10-06 20:36:30 +00:00
/* Changed rule in new modula-2 */
1986-03-20 14:52:03 +00:00
;
1986-04-17 09:28:09 +00:00
CaseLabelList(struct type **ptp; struct node **pnd;):
CaseLabels(ptp, pnd)
[
{ *pnd = MkNode(Link, *pnd, NULLNODE, &dot); }
',' CaseLabels(ptp, &((*pnd)->nd_right))
{ pnd = &((*pnd)->nd_right); }
]*
1986-03-20 14:52:03 +00:00
;
1986-10-06 20:36:30 +00:00
CaseLabels(struct type **ptp; register struct node **pnd;)
1986-04-06 17:42:56 +00:00
{
1986-10-06 20:36:30 +00:00
register struct node *nd1;
1986-04-06 17:42:56 +00:00
}:
1986-10-06 20:36:30 +00:00
ConstExpression(pnd)
{ nd1 = *pnd; }
1986-04-15 17:51:53 +00:00
[
1986-10-06 20:36:30 +00:00
UPTO { *pnd = MkNode(Link,nd1,NULLNODE,&dot); }
ConstExpression(&(*pnd)->nd_right)
{ if (!TstCompat(nd1->nd_type,
(*pnd)->nd_right->nd_type)) {
node_error((*pnd)->nd_right,
"type incompatibility in case label");
nd1->nd_type = error_type;
}
}
1986-04-15 17:51:53 +00:00
]?
1986-10-06 20:36:30 +00:00
{ if (*ptp != 0 && !TstCompat(*ptp, nd1->nd_type)) {
node_error(nd1,
"type incompatibility in case label");
}
*ptp = nd1->nd_type;
}
1986-03-20 14:52:03 +00:00
;
1986-09-25 19:39:06 +00:00
SetType(struct type **ptp;) :
1986-07-08 14:59:02 +00:00
SET OF SimpleType(ptp)
{ *ptp = set_type(*ptp); }
1986-03-20 14:52:03 +00:00
;
1986-03-29 01:04:49 +00:00
/* In a pointer type definition, the type pointed at does not
have to be declared yet, so be careful about identifying
type-identifiers
*/
1986-03-27 17:37:41 +00:00
PointerType(struct type **ptp;)
{
1986-10-06 20:36:30 +00:00
register struct node *nd = 0;
1986-03-27 17:37:41 +00:00
} :
POINTER TO
1986-07-08 14:59:02 +00:00
{ *ptp = construct_type(T_POINTER, NULLTYPE); }
[ %if ( lookup(dot.TOK_IDF, CurrentScope, 1)
1986-11-05 14:33:00 +00:00
/* Either a Module or a Type, but in both cases defined
in this scope, so this is the correct identification
*/
||
( nd = new_node(),
nd->nd_token = dot,
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.
???
*/
)
1986-10-06 20:36:30 +00:00
type(&((*ptp)->next))
{ if (nd) free_node(nd); }
1986-03-27 17:37:41 +00:00
|
1986-11-05 14:33:00 +00:00
IDENT { if (nd) {
/* nd could be a null pointer, if we had a
syntax error exactly at this alternation.
MORAL: Be careful with %if resolvers with
side effects!
*/
Forward(nd, (*ptp));
}
}
1986-03-27 17:37:41 +00:00
]
1986-03-20 14:52:03 +00:00
;
1986-07-08 14:59:02 +00:00
qualtype(struct type **ptp;)
{
register struct node *nd;
struct node *nd1; /* because &nd is illegal */
1986-07-08 14:59:02 +00:00
} :
qualident(&nd1)
{ nd = nd1;
*ptp = error_type;
if (ChkDesignator(nd)) {
if (nd->nd_class != Def) {
node_error(nd, "type expected");
1986-10-06 20:36:30 +00:00
}
else {
register struct def *df = nd->nd_def;
1986-07-08 14:59:02 +00:00
if (df->df_kind&(D_ISTYPE|D_FORWARD|D_ERROR)) {
if (! df->df_type) {
node_error(nd,"type \"%s\" not (yet) declared", df->df_idf->id_text);
}
else *ptp = df->df_type;
}
else {
node_error(nd,"identifier \"%s\" is not a type", df->df_idf->id_text);
}
}
}
FreeNode(nd);
}
;
1986-07-08 14:59:02 +00:00
1986-03-29 01:04:49 +00:00
ProcedureType(struct type **ptp;)
{
struct paramlist *pr = 0;
1986-10-06 20:36:30 +00:00
arith parmaddr = 0;
}
:
1986-07-08 14:59:02 +00:00
{ *ptp = 0; }
1986-10-06 20:36:30 +00:00
PROCEDURE
[
FormalTypeList(&pr, &parmaddr, ptp)
]?
{ *ptp = proc_type(*ptp, pr, parmaddr); }
1986-03-20 14:52:03 +00:00
;
1986-10-06 20:36:30 +00:00
FormalTypeList(struct paramlist **ppr; arith *parmaddr; struct type **ptp;)
1986-03-27 17:37:41 +00:00
{
1986-08-26 14:33:24 +00:00
struct type *tp;
1986-10-06 20:36:30 +00:00
int VARp;
1986-03-27 17:37:41 +00:00
} :
1986-10-06 20:36:30 +00:00
'('
1986-03-29 01:04:49 +00:00
[
1986-08-26 14:33:24 +00:00
var(&VARp) FormalType(&tp)
{ EnterParamList(ppr,NULLNODE,tp,VARp,parmaddr); }
1986-03-29 01:04:49 +00:00
[
1986-08-26 14:33:24 +00:00
',' var(&VARp) FormalType(&tp)
{ EnterParamList(ppr,NULLNODE,tp,VARp,parmaddr); }
1986-03-29 01:04:49 +00:00
]*
]?
')'
1986-07-08 14:59:02 +00:00
[ ':' qualtype(ptp)
1986-03-27 17:37:41 +00:00
]?
1986-03-20 14:52:03 +00:00
;
1986-07-08 14:59:02 +00:00
var(int *VARp;):
VAR { *VARp = D_VARPAR; }
|
/* empty */ { *VARp = D_VALPAR; }
;
1986-03-26 15:11:02 +00:00
ConstantDeclaration
{
1986-03-26 22:46:48 +00:00
struct idf *id;
1986-04-06 17:42:56 +00:00
struct node *nd;
1986-03-26 15:11:02 +00:00
}:
1986-07-08 14:59:02 +00:00
IDENT { id = dot.TOK_IDF; }
'=' ConstExpression(&nd)
{ define(id,CurrentScope,D_CONST)->con_const = nd; }
1986-03-20 14:52:03 +00:00
;
VariableDeclaration
{
1986-04-06 17:42:56 +00:00
struct node *VarList;
1986-06-06 02:22:09 +00:00
register struct node *nd;
1986-03-27 17:37:41 +00:00
struct type *tp;
1986-03-20 14:52:03 +00:00
} :
1986-06-06 02:22:09 +00:00
IdentAddr(&VarList)
{ nd = VarList; }
1986-08-26 14:33:24 +00:00
[ %persistent
1986-06-06 02:22:09 +00:00
',' IdentAddr(&(nd->nd_right))
{ nd = nd->nd_right; }
]*
1986-03-27 17:37:41 +00:00
':' type(&tp)
1986-06-10 13:18:52 +00:00
{ EnterVarList(VarList, tp, proclevel > 0); }
1986-03-20 14:52:03 +00:00
;
1986-04-15 17:51:53 +00:00
1986-06-06 02:22:09 +00:00
IdentAddr(struct node **pnd;) :
1986-06-04 09:01:48 +00:00
IDENT { *pnd = MkLeaf(Name, &dot); }
[ '['
ConstExpression(&((*pnd)->nd_left))
']'
]?
1986-04-15 17:51:53 +00:00
;