/* Copyright (c) 1979 Regents of the University of California */
* pi - Pascal interpreter code translator
* Charles Haley, Bill Joy UCB
* Version 1.2 January 1979
* Rvalue - an expression.
* Contype is the type that the caller would prefer, nand is important
* if constant sets or constant strings are involved, the latter
* because of string padding.
register struct nl
*p
, *p1
;
* Pick up the name of the operation
* for future error messages.
* The root of the tree tells us what sort of expression we have.
* Function call with arguments.
if (p
== NIL
|| p
->class == BADUSE
)
put2(O_RV1
+ (w
>> 1) | bn
<< 9, p
->value
[0]);
put3(O_RV
| bn
<< 9, p
->value
[0], w
);
* might consider a rvalue.
error("%s is a constant and cannot be qualified", r
[2]);
* Find the size of the string
if (contype
!= NIL
&& !opt('s')) {
if (width(contype
) < c
&& classify(contype
) == TSTR
) {
error("Constant string too long");
* Define the string temporarily
* so later people can know its
put2(O_CONC
, p
->value
[0]);
* Every other kind of constant here
put3(O_CON4
, p
->range
[0]);
put2(O_CON2
, p
->value
[1]);
put2(O_CON1
, p
->value
[0]);
* Function call with no arguments.
error("Can't qualify a function result value");
error("Type names (e.g. %s) allowed only in declarations", p
->symbol
);
error("Procedure %s found where expression required", p
->symbol
);
return (cset(r
, contype
, NIL
));
error("Operand of %s must be integer or real, not %s", opname
, nameof(q
));
put1(O_NEG2
+ (width(q
) >> 2));
return (isa(q
, "d") ? q
: nl
+T4INT
);
error("not must operate on a Boolean, not %s", nameof(q
));
if (p
== NIL
|| p1
== NIL
)
error("Left operand of %s must be Boolean, not %s", opname
, nameof(p
));
error("Right operand of %s must be Boolean, not %s", opname
, nameof(p1
));
put1(r
[0] == T_AND
? O_AND
: O_OR
);
if (p
== NIL
|| p1
== NIL
)
error("Left operand of / must be integer or real, not %s", nameof(p
));
error("Right operand of / must be integer or real, not %s", nameof(p1
));
return (gen(NIL
, r
[0], width(p
), width(p1
)));
* If the context hasn't told us
* the type and a constant set is
* present on the left we need to infer
* the type from the right if possible
* before generating left side code.
if (contype
== NIL
&& (rt
= r
[2]) != NIL
&& rt
[1] == SAWCON
) {
contype
= rvalue(r
[3], NIL
);
p
= rvalue(r
[2], contype
);
if (p
== NIL
|| p1
== NIL
)
if (isa(p
, "id") && isa(p1
, "id"))
return (gen(NIL
, r
[0], width(p
), width(p1
)));
if (isa(p
, "t") && isa(p1
, "t")) {
error("Set types of operands of %s must be identical", opname
);
gen(TSET
, r
[0], width(p
), 0);
* Note that set was filled in by the call
put2(NIL
, 0177777 << ((set
.uprbp
& 017) + 1));
error("Left operand of %s must be integer, real or set, not %s", opname
, nameof(p
));
error("Right operand of %s must be integer, real or set, not %s", opname
, nameof(p1
));
error("Cannot mix sets with integers and reals as operands of %s", opname
);
if (p
== NIL
|| p1
== NIL
)
error("Left operand of %s must be integer, not %s", opname
, nameof(p
));
error("Right operand of %s must be integer, not %s", opname
, nameof(p1
));
return (gen(NIL
, r
[0], width(p
), width(p1
)));
* Since there can be no, a priori, knowledge
* of the context type should a constant string
* or set arise, we must poke around to find such
* a type if possible. Since constant strings can
* always masquerade as identifiers, this is always
if (p1
== nl
+TSET
|| p1
->class == STR
) {
* For constant strings we want
* the longest type so as to be
* able to do padding (more importantly
* avoiding truncation). For clarity,
* we get this length here.
if (p1
== nl
+TSET
|| width(p
) > width(p1
))
* Now we generate code for
* the operands of the relational
p
= rvalue(r
[2], contype
);
if (nocomp(c
) || nocomp(c1
))
if (c1
!= TINT
&& c1
!= TDOUBLE
)
if (scalar(p
) != scalar(p1
))
if (c1
!= TPTR
&& c1
!= TNIL
)
if (r
[0] != T_EQ
&& r
[0] != T_NE
) {
error("%s not allowed on pointers - only allow = and <>");
if (width(p
) != width(p1
)) {
error("Strings not same length in %s comparison", opname
);
return (gen(g
, r
[0], width(p
), width(p1
)));
error("%ss and %ss cannot be compared - operator was %s", clnames
[c
], clnames
[c1
], opname
);
error("%s types must be identical in comparisons - operator was %s", clnames
[c1
], opname
);
if (rt
!= NIL
&& rt
[0] == T_CSET
)
error("... in [] makes little sense, since it is always false!");
if (p
== NIL
|| p1
== NIL
)
error("Right operand of 'in' must be a set, not %s", nameof(p1
));
if (incompat(p
, p1
->type
, r
[2])) {
cerror("Index type clashed with set component type for 'in'");
put4(O_IN
, width(p1
), set
.lwrb
, set
.uprbp
);
if (f
> MAXINT
|| f
< MININT
) {
error("Constant too large for this implementation");
* A floating point number
put(5, O_CON8
, atof(r
[2]));
* Constant strings. Note that constant characters
* are constant strings of length one; there is
* no constant string of length one.
error("%ss may not participate in comparisons", clnames
[c
]);